• 第13届 广东工业大学ACM程序设计大赛 C题 平分游戏


    第13届 广东工业大学ACM程序设计大赛 C题 平分游戏

    题目描述

    转眼间又过了一年,又有一届的师兄师姐要毕业了。

    ​ 有些师兄师姐就去了景驰科技实习。 在景驰,员工是他们最宝贵的财富。只有把每一个人的专业性和独特性结合在一起,他们才会获得成功。他们致力于为所有员工打造一个能够被激励,并分享公司成功的工作环境。
    创新精神:为了改变人类出行而不断迎接全新挑战。
    团队协作:依靠集体的智慧,坦诚无私地帮助彼此。
    结果导向:在所有方面都力争做到中国第一和世界一流,并对结果负责。
    共同成长:学习永无止境,通过个人发展和职业成长实现成就。
    GUDTACM集训队教练孙壕又来请大家大搓一顿。

    茶余饭足以后,有人提议不如来玩游戏吧。狼人杀谁是卧底跳一跳都已经玩得太多了,所以大家决定玩一个更加有挑战性的游戏。

    集训队一共有n位同学,他们都按照编号顺序坐在一个圆桌旁。第i位同学一开始有a[i]个硬币,他们希望使得每位同学手上的硬币变成相同的数目。每一秒钟,有且仅有一位同学可以把自己手上的一枚硬币交给另一位同学,其中这两位同学中间必须间隔k位同学。

    现在问的是最少几秒后所有同学手上的有相同数量的硬币

    输入描述:

    第一行输入两个整数n,k(1<=n<=1000000,0<=k<=n)
    接下来的一行有n个整数,第i个整数a[i](0<=a[i]<=1e9)表示第i位同学手上的硬币的数量。
    

    输出描述:

    一个整数,表示最少几秒后所有同学手上的有相同数量的硬币。如果不可能,则输出gg。
    

    示例1

    输入

    5 0
    2 3 1 5 4
    

    输出

    3
    

    思路:

    先看怎么处理没有(k)的限制的问题,保证总数整除(n)是必然的。

    再来处理硬币的转移问题,对于相邻的两个位置(A,B)来说,要么(A)(B),要么(B)(A),这样才能保证最优。

    我们假设(x_i)为 第 (i) 个人 给了 第 ((i - 1 + n) \%n) 个人 的硬币个数 ((x_i < 0)表示 后者给前者硬币)

    假设平均值为(avg),则有如下关系

    对于第0个人 (a_0 - x_0 + x_1 = avg ightarrow x_1 = x_0 - (a_0 - avg) ightarrow x_1 = x_0 - C_0 (C_0 = a_0 - avg))

    对于第1个人 (a_1 - x_1 + x_2 + avg ightarrow x_2 = x_1 - (a_1 - avg) ightarrow x_2 = x_0 - (a_0 + a_1 - 2*avg) ightarrow x_2 = x_0 - C_1(C_1 = a_0 + a_1 - 2 * avg))

    最后的答案就是最小化 (|x_0| + |x_1| + .... |x_{n-2}| = |x_0| +|x_0 - C_0| + |x_0 - C_1| + .... + |x_0 - C_{n-2}|)

    这个显然是在一个x轴上找到他们的中位数,答案最小。

    现在来考虑存在(k)的限制的问题,其实就将整个环分成了(gcd(n, k + 1))个独立的环,对每个环分别求解最后累加即可。

    代码:

    #include<bits/stdc++.h>
    #define LL long long
    #define P pair<int,int>
    using namespace std;
    const int N = 1e6 + 10;
    int a[N],vis[N];
    LL b[N];
    int n, k;
    LL cal(int cnt){
        b[cnt - 1] = 0;
        sort(b, b + cnt);
        return b[cnt / 2];
    }
    int main()
    {
        cin>>n>>k;
        k = min(k, n - 1);
        LL sum = 0;
        for(int i = 0;i < n;i++){
            scanf("%d",a + i);
            sum += a[i];
        }
        if(sum % n ){
            puts("gg");
            return 0;
        }
        LL ans = 0, avg = sum / n;
        for(int i = 0;i < n;i++){
           if(!vis[i]){
                int j = i,cnt = 0;
                LL tmp = 0,p = 0;
                while(!vis[j]){
                    vis[j] = 1;
                    b[cnt] = a[j] - avg + p, tmp += a[j];
                    p = b[cnt++];
                    j = (j + k + 1) % n;
                }
                if(tmp % cnt || tmp / cnt != avg){
                    puts("gg");
                    return 0;
                }
                LL midnum = cal(cnt);
                for(int k = 0;k < cnt;k++) ans += abs(midnum - b[k]);
           }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    PrintWriter、PrintStream的苦头 缓冲区问题
    BufferedImage与byte[]互转
    求两个日期的间隔天数
    Timer和TimerTask详解
    Java连接Access数据库
    根据value字段对map进行排序
    java collections读书笔记(3)Arrays
    java collections读书笔记(4) stack
    运行时异常与一般异常有何异同?(转)
    java collections读书笔记(7) bitset
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/8650297.html
Copyright © 2020-2023  润新知