• 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

     题意:现在定义一个操作,对于正整数,强调一下,是正整数,数字y的每一位的K次方-y=x,现在给定了x与k,求有多少种满足条件的y

    做法:x = F(y,k)-y

             因为  y > 0

             所以 x > F(y,k)

             因为 题目给定 x > 0

             所以  F(y,k) > y

             所以x > F(y,k) > y

             所以y的长度不超过x的长度10位,将y分成两部分,低位部分a和高位部分b

            设 F(Y,K) = F(a,k) +F(b,k);

            x = F(a,k) +F(b,k)-a- b*1e5;

            x-F(a,k)+a = F(b,k)-b*1e5

             y 的个数就是使上式成立的数字的个数

           于是枚举等式前边的数字,时间复杂度O(100000),预处理出来等式后边的,排序之后二分查找使之成立的个数即可

    感谢:https://blog.csdn.net/luricheng/article/details/70176894提供思路与坑点

    代码如下:

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<math.h>
    
    using namespace std;
    
    const long long maxn = 100050;
    
    long long F[maxn];
    long long t;
    long long x , k;
    long long ans[maxn];
    
    long long  poww(long long n ,long long m)
    {
        long long  res = 1;
        for(long long i=1; i<=m; i++)
        {
            res *= n;
        }
        return res;
    }
    
    void init()
    {
        memset(F , 0 , sizeof(F));
        for(long long i=0; i<100000; i++)
        {
            long long j = i;
            while( j )
            {
                F[i] += poww(j%10 , k);
                j /= 10;
            }
            ans[i] = F[i]-(i*100000);
        }
        sort(ans , ans+100000);
    }
    
    void debug()
    {
        for(long long i=0; i<=100; i++)
        {
            printf("%lld...%lld...%lld
    " , i , F[i] , ans[i]);
        }
    }
    
    long long sea(long long  xx)
    {
       long long  L , R;
       L = lower_bound(ans , ans+100000 , xx)-ans;
       if(ans[L] != xx)
        return 0;
       R = upper_bound(ans , ans+100000 , xx)-ans;
       R--;
       if(ans[R] != xx)
        return 0;
       return R-L+1;
    }
    
    long long solve()
    {
        long long  res;
        res = 0;
        for(long long i=0; i<100000; i++)
        {
            long long  tmp = sea(x-F[i]+i);
            res += tmp;
        }
        return res;
    }
    
    int main()
    {
        scanf("%lld" ,&t);
        for(long long cas=1; cas<=t; cas++)
        {
            scanf("%lld%lld" , &x , &k);
            init();
    //        debug();
            long long tmp = solve();
            if(x == 0)
                tmp--;
            printf("Case #%lld: %lld
    " , cas , tmp);
        }
    
    
        return 0;
    }
    View Code

    题意:现在你有一些数字卡片,每个数字卡片上写有1~9中的一个,给你的是每一个数字有多少张卡片,问你能够组成多少种不一样的等式。

    A+B=C 与 B+A=C 定义为不一样的

    思路:感谢https://www.cnblogs.com/jihe/p/6024135.html不然这个bug我能de一年

    直接暴力哪几个被选了就好,但是不能这样暴力,就是你现在选的是第x个,下一个选第几个,因为这样只让我们的暴力数量变多,我们其实想要的就是这个有没有被选就好了

    那么就从第一个开始,看他作为第i个的时候,下一个作为第i+1个,与此同时,下一层就是我不作为第i层,i+1作为第i层,这样可以覆盖所有的情况

    代码如下:

    /*
    错因: 首先不剪枝会WA
    其次,问的是会出现多少种不一样的,而不是多少个
    多少种的话,就可以整一个vis数组,最大容量是2,也就是2+3=5与3+2=5不一样
    但是容量是2的时候和直接保存两个有区别吗?
    试一下
    
    */
    
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    
    using namespace std;
    
    struct NODE
    {
        int a , b , c;
    } node[40];
    int t;
    int maxx;
    int a[15];
    int rem;
    int flag;
    
    void pre()
    {
        int tot = 0;
        for(int i=1; i<9; i++)
        {
            for(int j=1; i+j<=9; j++)
            {
                    node[tot].a = i;
                    node[tot].b = j;
                    node[tot].c = i+j;
    //                printf("%d..%d..%d..%d..
    " , tot , i , j , i+j);
                    tot++;
            }
        }
    }
    
    void init()
    {
        maxx = 0;
        flag = 1;
        rem = 0;
    }
    
    void input()
    {
        for(int i=1; i<=9; i++)
        {
            scanf("%d" , &a[i]);
            a[i] = min(a[i] , 17-i);
            rem += a[i];
            if(a[i] < 17-i)
                flag = 0;
        }
    }
    
    bool ok(int xx)
    {
        if(a[node[xx].a]>=0 && a[node[xx].b]>=0 && a[node[xx].c]>=0)
            return true;
        return false;
    }
    
    void dfs(int x , int dep , int sheng)
    {
        if(36-x+dep<=maxx)   ///后面的全都可以也不行的话 就直接跳出
            return ;
        if(dep >= 36)
            return ;
        a[node[x].a] -= 1;
        a[node[x].b] -= 1;
        a[node[x].c] -= 1;
        if(ok(x))
        {
            maxx = max(maxx , dep+1);
            dfs(x+1 , dep+1 , sheng-3);
        }
        a[node[x].a] += 1;
        a[node[x].b] += 1;
        a[node[x].c] += 1;
        dfs(x+1 , dep , sheng);
    }
    
    void solve()
    {
        dfs(0 , 0 , rem);
    }
    
    int main()
    {
        pre();
        scanf("%d" , &t);
        for(int cas=1; cas<=t; cas++)
        {
            init();
            input();
    //        printf("%d...
    " , rem);
            if(flag)
            {
                printf("Case #%d: 36
    " , cas);
                continue;
            }
            solve();
            printf("Case #%d: %d
    " , cas , maxx);
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    正方形_自适应_移动端
    meta name="viewport" content="width=device-width,initial-scale=1.0"
    :before/:after与::before/::after的区别 和属性content:值
    布局:flex弹性布局_兼容性写法
    布局:文本多列布局 column-* :
    布局:网格布局
    clear
    布局:盒模型 box-sizing : border-box ;
    object-fit : cover; 对象(图片和视频对象)
    布局:flex弹性布局_实践02
  • 原文地址:https://www.cnblogs.com/Flower-Z/p/9703607.html
Copyright © 2020-2023  润新知