链接:
https://vjudge.net/contest/253412#problem/H
题意:
给出若干堆石子,每次可以将其中一堆的一个石子移动到另一堆中,求最少的移动次数,使得每一堆都是某个数的倍数(大于1)
思路:
枚举质因子(每堆最后有多少个),为啥是质因子呢?比如枚举质因子2,如果每堆最后有4/8/16....个,对答案其实没影响,该整除还是整除。
然后对原来的堆进行取余操作得出的数表示还差多少个就满足要求,,sum1存余数的和,然后对余数按从大到小操作,ans加上相应的移动次数,sum1每次减去因子,归零时结束
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
set<LL>s;
vector<LL>v;
LL a[maxn];
void init(LL n)//查找素因数
{
for(LL i=2; i*i<=n; i++)
{
if(n&&n%i==0)
{
while(n%i==0)
{
n/=i;
}
s.insert(i);
}
}
if(n>1) s.insert(n);
}
int main()
{
int T;
scanf("%d",&T);
set<LL>::iterator it;
while(T--)
{
int n;
scanf("%d",&n);
s.clear();
LL sum=0;
for(int i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
sum+=a[i];
}
init(sum);
LL ans=1e10+10,sum1=0;
for(it=s.begin(); it!=s.end(); it++)
{
LL num1=*it;
v.clear();
sum1=0;
for(int i=1; i<=n; i++)
{
LL num2=a[i]%num1;
if(num2==0) continue;
v.push_back(num2);
sum1+=num2;
}
sort(v.begin(),v.end());
LL minx=0;
for(int i=(int)v.size()-1; i>=0; i--)
{
minx+=num1-v[i];
sum1-=num1;
if(sum1<=0) break;
}
ans=min(ans,minx);
}
printf("%lld\n",ans);
}
return 0;
}