2016 杭州区域赛补题

Posted flower-z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
" , cas);
        }
        else
        {
            long long tmp = sum/m;
//            printf("%lld..
" , tmp);
            for(long long i=1; i<=n; i++)
            {
//                printf("%lld...%lld..
" , 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
" , cas , num);
        }
    }


    return 0;
}
View Code

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..
" , 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..
" , 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...
" , i , maxx);
        }
        printf("Case #%d: %lld
" , cas , maxx);
    }

    return 0;
}


/*
100
99999999999999999999


1224591


224591
*/
View Code

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...
" ,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..
" , i , tmp);
            ans += tmp;
        }
        printf("Case #%d: %lld
" , cas , ans);
    }


    return 0;
}
View Code

 

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
" , cas , ans);
    }

    return 0;
}
View Code

 

以上是关于2016 杭州区域赛补题的主要内容,如果未能解决你的问题,请参考以下文章

2016CCPC东北赛补题

4/16 省赛补题

8月5号团队赛补题

[水]浙大校赛补题

NC月赛补题

2018/11/30 周五集训队第七次测试赛补题题解