2016 杭州区域赛补题

A - ArcSoft‘s Office Rearrangement

HDU - 5933

题意:现在有n个办公区,每个办公区内有a[i]个办公人员,现在要将这些人均匀的分布在m个办公区内,每个办公区人员必须等价。现在有两个操作,1操作,可以将相邻的两个区域的人员结合在一起,2操作可以将一个办公区的人员,随意划分成两部分,两部分不一定平均,问最少需要多少次操作。

做法:贪心,从前向后枚举,不可以的情况就是不能平均的,可以预处理出来平均值,对于可以的情况,如果比平均值小,就直接加在后一个办公区内,要是与平均值一样,就可以直接跳过,要是大于平均值,就先划分成平均值的若干份,最后不足一个平均值的加在后一个办公区内。

代码如下:

#include<stdio.h>
#include<iostream>

using namespace std;

long long t;
long long n , m;
long long a[100005];
long long sum;
long long num;

int main()
{
    scanf("%lld" , &t);
    for(long long cas = 1; cas<=t; cas++)
    {
        scanf("%lld%lld" , &n , &m);
        sum = 0;
        num = 0;
        for(long long i=1; i<=n; i++)
        {
            scanf("%lld" , &a[i]);
            sum += a[i];
        }
        if(sum % m != 0)
        {
            printf("Case #%lld: -1\n" , cas);
        }
        else
        {
            long long tmp = sum/m;
//            printf("%lld..\n" , tmp);
            for(long long i=1; i<=n; i++)
            {
//                printf("%lld...%lld..\n" , i , a[i]);
                if(a[i] > tmp)
                {
                    num += (a[i]/tmp)-1;
                    if(a[i]%tmp != 0)
                    {
                        num ++;   //先剥离下来
                        num++;    //再安装到下一个块上去
                        a[i+1] += a[i]%tmp;
                    }
                }
                else if(a[i] == tmp)
                {
                    continue;
                }
                else if(a[i]<tmp && a[i]!=0)
                {
                    num++;
                    a[i+1] += a[i];
                }
            }
            printf("Case #%lld: %lld\n" , cas , num);
        }
    }

    return 0;
}

F - Four Operations

HDU - 5938

题意:给你一个字符串,5<=len<=20,字符串由1~9的数字组成,问你向里面按顺序添加+ - * / 构成的算术运算式子结果最大是多少

做法:我们知道肯定让x+y尽可能的大,a*b/c的结果尽可能小,于是a*b的结果尽可能小,c尽可能大。

于是我们枚举“/”的位置,后面的作为c,a,b都只占一位 前面的作为x+y,一直x+y的长度之后,例如12121,那么和要尽可能大,要么就是1+2121,要么就是1212+1,因为这样可以保证尽可能长的长度,为什么要枚举除法的位置,而不是直接取最后一位,给前面省长度呢,因为可能a*b很大,c很小,导致我们减去的东西很大,比一位所带来的影响还要大,例如224591,所以需要枚举"/"的位置

代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>

using namespace std;

int t;
char s[25];
int len;
long long sum[25];
long long maxx;

long long num(int l , int r)
{
    long long res = 0;
    for(int i=l; i<=r; i++)
    {
        res = res*10+(s[i]-‘0‘);
    }
    return res;
}

int main()
{
    scanf("%d" , &t);
    for(int cas=1; cas<=t; cas++)
    {
        scanf("%s" , s);
        len = strlen(s);
        maxx = -100000000000000000;
//        printf("%lld..\n" , maxx);
        for(int i=0; i<len; i++)
        {
//            sum[i] =0;
//            for(int j=0; j<i; j++)
//            {
//                sum[i] = max(sum[i] , num(0,j)+num(j+1,i));
//            }
          sum[i] = max(num(1,i)+(s[0]-‘0‘) , num(0,i-1)+(s[i]-‘0‘));
//          printf("%d..%lld..\n" , i , sum[i]);
        }
        for(int i=4; i<len; i++)
        {
            maxx = max(maxx , sum[i-3]-((s[i-2]-‘0‘)*(s[i-1]-‘0‘)/num(i,len-1)));
//            printf("%d...%lld...\n" , i , maxx);
        }
        printf("Case #%d: %lld\n" , cas , maxx);
    }

    return 0;
}

/*
100
99999999999999999999

1224591

224591
*/

C - Car

HDU - 5935

题意:现在一个人驾车行驶,保证全程不减速,现在给出了n个测速点,保证测速点一定是在整秒的时候测量的,问这个人通过这n个测速点最快的时间

做法:正向的,全程不减速不好写,对于每一段,你无法确定速度与时间,如果这一段比上一段长,你就直接设置成一秒,那万一下一段很短,岂不是前面的设置都错了;

于是我们反向想,倒过来就是全程不加速,那么最后一段一定是一秒,速度最大,这样可以保证全程时间尽可能的短,于是最后一段的时间与速度都是知道的,那么前一段的速度要小于这一段,时间要尽可能的短,于是整除向上取整即可,记得更新速度,即可解决

坑点:不能直接计算速度v  精度卡的非常的死  必须保存距离与时间

代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>

using namespace std;

int t;
int n;
long long b[100005];
long long a[100005];
//long long num1 , num2;

void debug()
{
    for(int i=1; i<=n; i++)
    {
        printf("%d..%lld...\n" ,i , a[i]);
    }
}

int main()
{
    scanf("%d" , &t);
    for(int cas=1; cas<=t; cas++)
    {
        scanf("%d" , &n);
//        num1 = 0;
        b[0] = 0;
        for(int i=1; i<=n; i++)
        {
            scanf("%lld" , &b[i]);
//            a[i] = num2-num1;
//            num1 = num2;
        }
        sort(b+1 , b+1+n);
        for(int i=1; i<=n; i++)
        {
            a[i] = b[i]-b[i-1];
        }
//        debug();
        long long ans = 1;
//        double v = a[n]*1.00;
        long long tmp;
        tmp = 1;
        for(int i=n-1; i>=1; i--)
        {
            tmp = ceil((1.00*a[i]*tmp)/a[i+1]);
//            printf("%d..%lld..\n" , i , tmp);
            ans += tmp;
        }
        printf("Case #%d: %lld\n" , cas , ans);
    }

    return 0;
}

B - Bomb

HDU - 5934

题意:现在有一对炸弹,要全部都引爆,每个炸弹有自己的圆心和半径,引爆之后在范围内的炸弹都会被引爆,问引爆所有炸弹所需要的最小的花费。n<=1e3

做法:刚开始的做法是,首先,我们可以根据引爆范围n^2的建图,有向图,入度为零的是一定要点的,它所能到达的点全部都删去, 剩下的就是在连通块中找最小花费的点了。剩下的这部分我是直接联通快中招最小点的。 这样是一定不对的,例如,1-2 2-3 3-1 2-4 4的值最小,但是引爆4并不能引爆1,2,3. 于是,只有在同一个强连通分量里面才可以求最小值,剩下的就是入度为零的全部引爆了 于是,先缩点,形成DAG之后求 Tarjan的时间复杂度O(n+m) 缩点时间复杂度O(n^2) 求解O(n)

代码如下:

/*
刚开始的做法是:首先,我们可以根据引爆范围n^2的建图,有向图,入度为零的是一定要点的,它所能到达的点全部都删去,
剩下的就是在连通块中找最小花费的点了。剩下的这部分我是直接联通快中招最小点的。
这样是一定不对的,例如,1-2 2-3 3-1 2-4 4的值最小,但是引爆4并不能引爆1,2,3.
于是,只有在同一个强连通分量里面才可以求最小值,剩下的就是入度为零的全部引爆了
于是,先缩点,形成DAG之后求
Tarjan的时间复杂度O(n+m)
缩点时间复杂度O(n^2)
求解O(n)
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>

using namespace std;

const int maxn = 1003;

int t;
int n;

struct CIRCLE
{
    double x,y;
    double r;
    int c;
}circle[maxn];

double dis(int i , int j)
{
    return sqrt((circle[i].x-circle[j].x)*(circle[i].x-circle[j].x)+(circle[i].y-circle[j].y)*(circle[i].y-circle[j].y));
}

void input()
{
    for(int i=1; i<=n; i++)
    {
        scanf("%lf%lf%lf%d" , &circle[i].x , &circle[i].y , &circle[i].r , &circle[i].c);
    }
}

struct EDGE
{
    int to , next;
}edge[maxn*maxn];
int head[maxn] , tot;
//int head2[maxn] , tot2;
int ans;
int du[maxn];

int low[maxn] , dfn[maxn] , Stack[maxn] , num[maxn];///num记录缩点之后每个点的大小
int belong[maxn];
int index , scc , top;
bool InStack[maxn];

void init()
{
    memset(head , -1 , sizeof(head));
    tot = 0;
//    memset(head2 , -1 , sizeof(head2));
//    tot2 = 0;
    ans = 0;
    for(int i=1; i<=n; i++)
    {
        num[i] = 10004;
    }
    memset(du , 0 , sizeof(du));
}

void add(int u , int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}

//void add2(int u , int v)
//{
//    edge2[tot2].to = v;
//    edge2[tot2].next = head2[u];
//    head2[u] = tot2++;
//}

void build()
{
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(j == i) continue;
            if(dis(i , j) <= circle[i].r)
            {
                add(i , j);
            }
        }
    }
}

void Tarjan(int u)
{
    int v;
    low[u] = dfn[u] = ++index;
    Stack[top++] = u;
    InStack[u] = true;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        v = edge[i].to;
        if( !dfn[v] )
        {
            Tarjan(v);
            if( low[u] > low[v] )
            {
                low[u] = low[v];
            }
        }
        else if(InStack[v] && low[u] > dfn[v])
        {
            low[u] = dfn[v];
        }
    }
    if(low[u] == dfn[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            InStack[v] = false;
            belong[v] = scc;
            num[scc] = min(num[scc] , circle[v].c);
        }while(v!=u);
    }
}

void solve()
{
    memset(dfn , 0 , sizeof(dfn));
    memset(InStack , false , sizeof(InStack));
    index = scc = top = 0;
    for(int i=1; i<=n; i++)
    {
        if( !dfn[i] )
        {
            Tarjan(i);
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=head[i]; j!=-1; j=edge[j].next)
        {
            int tmp = edge[j].to;
            if(belong[i] != belong[tmp])
            {
//                add2(belong[i] , belong[tmp]);
                  du[belong[tmp]]++;
            }
        }
    }

}

int main()
{
    scanf("%d" , &t);
    for(int cas=1; cas<=t; cas++)
    {
        scanf("%d" , &n);
        init();
        input();
        build();
        solve();
        for(int i=1; i<=scc; i++)
        {
            if(du[i] == 0)
            {
                ans += num[i];
            }
        }
        printf("Case #%d: %d\n" , cas , ans);
    }

    return 0;
}

原文地址:https://www.cnblogs.com/Flower-Z/p/9703607.html

时间: 2024-10-10 03:04:33

2016 杭州区域赛补题的相关文章

HDU 4463 Outlets (prime_杭州区域赛水题)

Problem Description In China, foreign brand commodities are often much more expensive than abroad. The main reason is that we Chinese people tend to think foreign things are better and we are willing to pay much for them. The typical example is, on t

hdu 4463 有一条边必须加上 (2012杭州区域赛K题)

耐克店 和 苹果店必须相连 Sample Input42 30 01 00 -1 1 -10 Sample Output3.41 1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 # include <cmath> 6 # define LL long long 7 using namespace std ; 8

13杭州区域赛现场赛Rabbit Kingdom(树状数组+离线)

题意:给你一个长度数列,再给你m个询问(一个区间),问你在这个区间里面有多少个数与其他的数都互质. 解题思路:你看这种类型的题目都可以肯定这是 离线+树状数组(线段树).主要就是他的更新信息.这里我的处理是先把1-200000(每个数的范围)数里面所有的质因子求出来.然后从后往前遍历数组.会出现以下几种情况 1.a[k]的质因子在后面出现过而[更新标记] 和[被更新标记] 都为假 2.a[k]的质因子在后面出现过的那个位置 I   [更新标记]为 真 . 3.a[k]的质因子在后面出现过且那个位

[暑假集训]区域赛套题集

2014-07-03 [浙江第11届省赛]ZOJ 3785 What day is that day?  (打表找循环节) [暑假集训]区域赛套题集

Heshen&#39;s Account Book HihoCoder - 1871 2018北京区域赛B题(字符串处理)

Heshen was an official of the Qing dynasty. He made a fortune which could be comparable to a whole country's wealth by corruption. So he was known as the most corrupt official in Chinese history. But Emperor Qianlong liked, or even loved him so much

第十届山东省acm省赛补题(2)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4124 L Median Time Limit: 1 Second      Memory Limit: 65536 KB Recall the definition of the median of  elements where  is odd: sort these elements and the median is the -th largest element.

2017年ICPC中国大陆区域赛真题(下)

2017年ICPC中国大陆区域赛真题(下) A - Lovers #include <bits/stdc++.h> using namespace std; const int maxn=2e5+10; int n,k,a[maxn],b[maxn],ans; int main() { int _; scanf("%d", &_); while (_--) { scanf("%d%d", &n, &k); for (int i =

hdu5080:几何+polya计数(鞍山区域赛K题)

/* 鞍山区域赛的K题..当时比赛都没来得及看(反正看了也不会) 学了polya定理之后就赶紧跑来补这个题.. 由于几何比较烂写了又丑又长的代码,还debug了很久.. 比较感动的是竟然1Y了.. */ 题目大意: 给定一些点,某些点上有边,问用k种颜色染色的等价类有多少种 思路: 由于坐标是整数..只有可能旋转90,180,270才能得到置换 且图形必须为中心对称图形 先用几何方法找出对称中心 然后旋转,找是否出现置换... 由于点数只有50,几何预处理这一部分可以很暴力无脑的写..各种判断相

HDU 4438 Hunters 区域赛水题

本文转载于 http://blog.csdn.net/major_zhang/article/details/52197538 2012天津区域赛最水之题: 题意容易读懂,然后就是分情况求出A得分的数学期望,所谓数学期望就是在该概率下的平均得分. 现在就是两种方案,Alice要根据输入给出的数据情况选出最优方案,也就是先选老虎,还是狼. 1.A先选老虎: a.B也先选老虎,则得分为Q(P*X+P*Y); //打完老虎还要打狼 b.B选狼,则两人可以直接获得猎物,则得分为(1-Q)*X 所以1方案