牛客 - 平分游戏

题目:https://www.nowcoder.com/acm/contest/90/C

题意:
n个人围坐一个圆,每人初始a[i]个硬币;
每秒钟有且仅有一个人把一个硬币给另一个人,两人必须相隔k人;
求最少多少秒后,使得每人手中硬币数相等。

分析:
设其中num个人是可以相互给硬币的(组成一个小环),如下
(1)–X1–>(2)–X2–>(3)–X3–>……–Xnum-1–>(num)–Xnum–>(1)
其中,Xi代表i给i+1多少枚硬币,可以为负;
设每个人最后手中的硬币数为M,得到等式:
a[1]+x6-x1=M;
a[2]+x1-x2=M;
a[3]+x2-x3=M;
.
.
a[num]+X(num-1)-Xnum=M;
即:
x1=x1;
x2=x1-(M-a[2]);
x3=x1-(M-a[2]-a[3]);
.
.
xnum=x1-(M-a[2]-a[3]-…-a[num]);
即:
xi=x1-(M-∑aj); (2<=j<=i)
所求即为:
|x1|+|x2|+…+|xnum|
实际就是x1到(M-∑aj)的距离;
求中位数,即可得到。

注意:认为k==n使不能传递硬币(谁tm知道题意是这样的,擦)。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int tmax=1e6+5;
int n,k,p[tmax],num;
ll a[tmax],M,sum[tmax],x,ans;
bool v[tmax];
int main()
{
    cin>>n>>k;
    int i,j;
    for(i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        M+=a[i];
    }
    if(M%n>0)
    {
        printf("gg");
        return 0;
    }
    M/=n;
    if(k==n)
    {
        for(i=1;i<=n;i++)
          if(a[i]!=M)
          {
             printf("gg");
             return 0;
          }
    }
    for(i=1;i<=n;i++)
    {
        if(v[i]==true) continue;
        num=0;
        sum[1]=0;
        for(j=i;v[j]==false;)
        {
            v[j]=true;
            p[++num]=j;
            j=(j+k+1)%n;
            if(j==0) j=n;
        }
        for(j=2;j<=num;j++)
            sum[j]=sum[j-1]+a[p[j]];
        if(sum[num]+a[p[1]]!=num*M)
        {
            printf("gg");
            return 0;
        }
        for(j=2;j<=num;j++)
            sum[j]=(j-1)*M-sum[j];
        sort(sum+1,sum+1+num);
        x=sum[(num+1)/2];
        for(j=1;j<=num;j++)
          ans+=abs(x-sum[j]);
    }
    printf("%lld",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值