6019: 石子游戏
时间限制: 1 Sec 内存限制: 128 MB提交: 120 解决: 34
[ 提交][ 状态][ 讨论版][命题人: 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
来源
最后得到的数都是x的倍数,所以x必然是素数,若保证最后得到的数是x的倍数,则需要所有数的和是x的倍数。求素数O(nlogn),枚举素数。求每个数跟x的模除的余数,算出总的余数可以构成多少个x,余数从大到小开始凑,维护一个余数和,当余数和整除x等于前面得到的数的时候,就可以跳出循环。(借鉴)
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int prim[100005], a[100005], book[100005], m[100005], k=0;
void prime()
{
memset(book, 0, sizeof(book));
for(int i=2;i<=10000;i++)
if(!book[i])
{
prim[k++]=i;
for(int j=i*i;j<=100000;j+=i)
book[j]=1;
}
}
int main()
{
prime();
long long n, sum=0;
scanf("%lld", &n);
for(int i=0;i<n;i++)
{
scanf("%d", &a[i]);
sum+=a[i];
}
long long minn=1e18;
for(int i=0;i<k;i++)
{
if(sum%prim[i])
continue;
long long temp=0;
for(int j=0;j<n;j++)
{
m[j]=a[j]%prim[i];
temp+=m[j];
}
temp/=prim[i];
sort(m, m+n);
long long cnt=0, sum3=0;
for(int j=n-1;j>=0;j--)
{
cnt++;
sum3+=prim[i]-m[j];
if(cnt==temp)
{
minn=min(minn, sum3);
break;
}
}
}
printf("%lld\n", minn);
return 0;
}
/**************************************************************
Problem: 6019
User: ldu_reserver201701
Language: C++
Result: 正确
Time:108 ms
Memory:2656 kb
****************************************************************/