石子游戏
时间限制: 1 Sec 内存限制: 128 MB提交: 118 解决: 32
[ 提交][ 状态][ 讨论版][命题人: admin]
题目描述
在Bob学会怎样玩Nim Game之后,他打算尝试另一款看起来更为简单的石子游戏
这个游戏是这样子玩的:一共有一个玩家,且一开始有N堆石头,第i堆石头有ai个石子。玩家每次只能移动一个石子从一堆到另一堆。在每次移动结束后,如果存在一个整数x(x>1)满足任意一堆的当前石子数bi都是x的倍数,那么游戏结束。现在你需要帮助Bob计算出为了结束这个无聊的游戏,他最少需要移动的次数。特别的, 0是任何正整数的倍数。
这个游戏是这样子玩的:一共有一个玩家,且一开始有N堆石头,第i堆石头有ai个石子。玩家每次只能移动一个石子从一堆到另一堆。在每次移动结束后,如果存在一个整数x(x>1)满足任意一堆的当前石子数bi都是x的倍数,那么游戏结束。现在你需要帮助Bob计算出为了结束这个无聊的游戏,他最少需要移动的次数。特别的, 0是任何正整数的倍数。
输入
第一行一个整数N,表示石子的堆数
第二行N个整数,表示每堆石子的数量
第二行N个整数,表示每堆石子的数量
输出
一行一个整数,即最少的移动次数。如果一开始就满足游戏结束的条件,请输出0
样例输入
5
1 2 3 4 5
样例输出
2
提示
从第1堆移动一个到第5堆,从第4堆移动一个到第2堆
得到:0 3 3 3 6
满足都是3的倍数
数据规模
对于30%的数据,1<=N<=100
对于60%的数据,1<=N<=5000
对于100%的数据,1<=N<=100,000,1<=ai<=100,000
来源
【思路】
起初以为是个博弈, 分析了后 , 题目要求是 n个数是某个x的倍数, 也就是说 他们的GCD >1
所以可以枚举素数, 然后对 可以满足的情况进行分析, 把% 后的 从小的往大的上放
【code】
#include <iostream>
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const ll INF=(1ll<<63-1);
const int MAXN=5e5+5;
using namespace std;
int vis[MAXN];
ll a[MAXN];
ll b[MAXN];
ll prime[MAXN];
int cont;
void init()
{
mem(vis,0);
cont=0;
for(int i=2;i<=1e6+10;i++)
{
if(!vis[i])
{
prime[++cont]=i;
}
for(int j=1;j<=cont&&i*prime[j]<=1e6+10;j++)
{
vis[ i*prime[j]] =1;
if((i%prime[j])==0)
break;
}
}
}
int main()
{
init();
int n;
cin>>n;
ll sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
int c=0;
ll av=sum/n;
for(int i=1;i<=n;i++)
{
if(a[i]%av==0)
c++;
}
if(c==n)
{
cout<<0<<endl;
return 0;
}
ll ans=INF;
for(int i=1;i<=cont;i++)
{
if(sum%prime[i]==0)
{
ll s=0;
mem(b,0);
for(int j=1;j<=n;j++)
{
b[j]=a[j]%prime[i];
s+=b[j];
}
s=s/prime[i];
sort(b+1,b+n+1);
ll res=0,s2=0,s3=0;
for(int j=n;j>=1;j--)
{
s3+= (b[j]+prime[i]-b[j]%prime[i]);
s2= s3/prime[i];
res+= (prime[i]-b[j]%prime[i]);
if(s2==s)
{
ans=min(ans,res);
break;
}
}
}
}
cout<<ans<<endl;
return 0;
}
1223