HDU 6237 A Simple Stone Game
HDU 6237 A Simple Stone Game
题目大意:
有n堆石子,每一堆都有ai块。
每次可以任意将一个石子从一堆移动到另外一堆,代价为1.
让最后的每一堆石子都是一个质数的倍数(默认0为任何数的倍数)
求最小代价?
思路:
因为如果有一个数x,最后每一堆石子的个数都是它的倍数,那么所有石子的和一定也是x的倍数。
求每一堆石子的和sum,然后将其分解质因数。
然后对每一个质因数进行验证。
怎么验证呢?贪心即可。对每组数取一个x的模。取模之后的数从小到大排序,将少的移动到多的上面。如果再一次到达x,那么最大的堆变成零,多出来的往次大堆上放。
#include<bits/stdc++.h>
#define MAXN 100010
#define ll long long
using namespace std;
int n,T,maxx,cnt,cnt2;
ll sum;
int a[MAXN],prime[MAXN],cur[MAXN],not_prime[MAXN],Prime[MAXN];
inline void pre_solve(){
not_prime[1]=1;
for(int i=2;i<=100000;i++){
if(not_prime[i]==0){
prime[++cnt]=i;
}
for(int j=1;j<=cnt&&prime[j]*i<=100000;j++){
not_prime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
inline int ll calc(ll x){
ll cur_ans=0;
memcpy(cur,a,sizeof(int)*(n+1));
for(int i=1;i<=n;i++) cur[i]%=x;
sort(&cur[1],&cur[n+1]);
int l=1,r=n;
while(l<r){
while(cur[l]%x==0) l++;
while(cur[r]%x==0) r--;
int cur_sum=cur[l]%x;
cur_ans+=cur_sum;
while((cur[r]+cur_sum)>x){
cur_sum-=x-cur[r];
r--;
}
cur[r]+=cur_sum;
l++;
}
return cur_ans;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d",&T);
pre_solve();
while(T--){
sum=0,maxx=0,cnt2=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum+=a[i];
maxx=max(maxx,a[i]);
}
long long ans=sum-maxx;
int pre=2;
for(int i=pre;i<=(int)sqrt(sum);i++){
if(not_prime[i]==true||sum%i!=0) continue;
else{
Prime[++cnt2]=i;
pre=i;
while(sum%i==0) sum/=i;
}
}
//
// for(int i=1;i<=cnt2;i++) printf("%d ",Prime[i]); puts("");
for(int i=1;i<=cnt2;i++){
ans=min(ans,calc(Prime[i]));
}
if(sum!=1) ans=min(ans,calc(sum));
printf("%lld\n",ans);
}
return 0;
}