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;
}
- 列表内容