OC Round #9 简单的取石子游戏

10165 : 简单的取石子游戏
时间限制: 1000 MS 内存限制: 131072 KB 提交总数: 28 AC总数: 11
问题描述
现在有n堆石子,且已知每堆石子的数量,每次操作你可以从任一堆中取一颗石子放到另一堆中,问最少操作几次使得每一堆石子的数量均是某一个数的倍数。
输入格式
首先,输入一个n,代表有n堆石子。
第二行有n个数,第i个数记为a[i],代表第i堆得初始石子数。
【数据范围】
1<=n<=100000,1<=a[i]<=100000。
输出格式
输出最少操作次数。
样例输入
样例输入1:
5
1 2 3 4 5
样例输入2:
2
5 7
样例输出
样例输出1:
2
样例输出2:
1

#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 100010
using namespace std;
typedef unsigned long long ull;
int a[N],n,g[N],gp,c[N];
ull sum,ans=1<<31,cnt;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];
    for(ull x=2;x*x<=sum;x++)//分解质因数 
    while(sum%x==0)g[++gp]=x,sum/=x;
    if(sum>1)g[++gp]=sum;//手误,写成sum>0
    for(int i=1,w;i<=gp;i++)
    {
        sum=w=cnt=0;
        memset(c,0,sizeof c);
        for(int j=1,t;j<=n;j++)
        {
            t=a[j]%g[i];
            if(t>0)c[++w]=t,sum+=t;//需要花费步数来达到状态 
        }
        sort(c+1,c+w+1);
        for(int j=w;j;j--)//倒序,这样移动的步数会少 
        {
            cnt+=g[i]-c[j];
            sum-=g[i];//至多w堆石子加上这堆刚好都是b[i]的倍数 
            if(sum<=0)break;
        }
        ans=min(ans,cnt);
    }
    printf("%lld",ans);
    return 0;
} 
  • 列表内容
原文地址:https://www.cnblogs.com/wuzetian/p/9900409.html