After he has learned how to play Nim game, Bob begins to try another stone game which seems much easier.
The game goes like this: one player starts the game with NN piles of stones. There is aiai stones on the iith pile. On one turn, the player can move exactly one stone from one pile to another pile. After one turn, if there exits a number x(x>1)x(x>1) such that for each pile bibi is the multiple of xx where bibi is the number of stone of the this pile now), the game will stop. Now you need to help Bob to calculate the minimum turns he need to stop this boring game. You can regard that 00 is the multiple of any positive number.
Input
The first line is the number of test cases. For each test case, the first line contains one positive number N(1≤N≤100000)N(1≤N≤100000), indicating the number of piles of stones.
The second line contains NN positive number, the iith number ai(1≤ai≤100000)ai(1≤ai≤100000)indicating the number of stones of the iith pile.
The sum of NN of all test cases is not exceed 5∗1055∗105.
Output
For each test case, output a integer donating the answer as described above. If there exist a satisfied number xx initially, you just need to output 00. It's guaranteed that there exists at least one solution.
Sample Input
2 5 1 2 3 4 5 2 5 7
Sample Output
2 1
题意就是给你N堆石头 每次可以将一块石头从一堆移动到另一堆,求最小的移动次数使每一堆都是某个数 X的倍数
理解:每一堆都是X的倍数那么石头的总数必然是X的倍数,那么就可以枚举石头总数的质因子,求出符合条件的最小次数便可以
枚举质因子可以用欧拉筛打表预处理一下素数表,然后枚举素数,如果不能整除则跳过,由于答案必然不会很大所以不会超时。
接着关键在于怎么判定该质因子满足条件并且求出转移次数。
这里用了一个技巧,现将b[i]=a[i]%prime[j] 求出, 然后对b sort一下 然后从最左边l 和最右边r 开始 令tt=min(prime[j]-b[r], b[l])
然后令b[l]-=tt , b[r]+=tt (就是将前面补到后面) 若左边b[l]=0 则l右移 ,若右边b[r] =prime[j] 则r 左移
然后求所有结果的最小值 代码如下
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxl=500000+10;
bool check[maxl];
int prime[500005];
int a[100005];
int b[100005];
int tot=0;
long long ans=0;
long long Min;
int Max=-1;
int T;
int N;
int main()
{
memset(check , 0 , sizeof(check));
for(int i = 2 ; i < maxl ; ++i)
{
if(!check[i])prime[tot++] = i;
for(int j = 0 ; j < tot ; j++)
{
if(i * prime[j] > maxl)break;
check[i * prime[j]] = 1;
if ( i % prime[j] == 0 )break;
}
}
scanf("%d",&T);
while(T--)
{
ans=0;
Max=-1;
scanf("%d",&N);
for(int i=1;i<=N;i++)
{
scanf("%d",&a[i]);
Max=max(Max,a[i]);
ans+=a[i];
}
Min=ans-Max;
for(int j=0;j<tot&&prime[j]<=ans;j++)
{
if(ans%prime[j]!=0)continue;
for(int k=1;k<=N;k++)
{
b[k]=a[k]%prime[j];
}
sort(b+1,b+1+N);
long long l=1;
long long r=N;
long long result=0;
while(l<r)
{
int tt=min(b[l],prime[j]-b[r]);
b[l]-=tt;
b[r]+=tt;
result+=tt;
if(b[l]==0)l++;
if(b[r]==prime[j])r--;
}
Min=min(Min,result);
}
printf("%lld\n",Min);
}
return 0;
}
两个注意点:最大值的设置不要设为1e18 考虑到所有数的和可能刚好是一个很大的素数 此时所打的素数表可能不够整除,此时输出的结果必然是所有数的和减去最大的数(将其他石头都移到这个最大的堆上)所以要将Min设置为总和减去最大堆。(wa了八发)
不能直接统计对每个堆的最小操作数(会wa具体原因不知)