题解 模拟赛 【stone】
模拟赛 【stone】
题目大意:

solution:
显然最后每个数都是 \(x\) 的倍数,那么它们的和必是 \(x\) 的倍数, \(x\) 必是和的因数且是质因数。
简单证明\(^1\):
设最后每个数为 \(k_1x\)、\(k_2x\)、\(k_3x\)...\(k_{n-1}x\)、\(k_nx\)。它们的和\(sum=k_1x+k_2x+k_3x+...+k_{n-1}x+k_nx\),根据分配律 \(sum=(k_1+k_2+k_3+...+k_{n-1}+k_n)x\)。所以和是 \(x\) 的倍数。
证毕。
简单证明\(^2\):
反证法:
若 \(x\) 不是和的质因数,根据唯一分解定理 \(x\) 必有一个质因子是 \(sum\) 的因数。用更小的质因数更优,贪心的想,移动次数更少。所以 \(x\) 是 \(sum\) 的质因数。
证毕。
然后我们就可以枚举 \(sum\) 的质因数,再枚举每堆石子,看比成为 \(x\) 倍还多几个,存起来。然后从大到小排序,因为越多,离 \(x\) 的倍数差的越少,能移动次数最少。求个组数,然后把差累加进总数再和答案取个 \(\min\) 就行了。
细节处理:
- 开 \(\text{long long}\) ;
- 答案初始值赋大点;
- 先线性筛出质数会比根号分解快点。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5;
typedef long long LL;
LL a[N],b[N],sum,ans;
LL pr[N],cnt;
bool check[N];
inline void init() {//线性筛
for(int i=2; i<N; i++) {
if(!check[i]) pr[++cnt]=i;
for(int j=1; j<=cnt; j++) {
if(i*pr[j]>N) break;
check[i*pr[j]]=1;
if(i%pr[j]==0) break;
}
}
}
LL yue[N],num;
inline void dec(LL x) {//质因数分解
for(int i=1; i<=cnt; i++) {
if(x%pr[i]==0) yue[++num]=pr[i];
while(x%pr[i]==0) x/=pr[i];
}
if(x>1) yue[++num]=x;
}
int main() {
init();
sum=0,ans=9223372036854775807;
int n;
scanf("%d",&n);
for(int i=1; i<=n; i++) {
scanf("%lld",&a[i]);
sum+=a[i];
}
dec(sum);
for(int i=1; i<=num; i++) {//枚举质因数
LL res=0,he=0;
LL x=yue[i];
for(int j=1; j<=n; j++) {
b[j]=a[j]%x;//看比 x 的倍数多几个
he+=b[j];//存起来
}
sort(b+1,b+n+1);//从大到小排序
LL ge=he/x;//求组数
for(int j=n; j>=n-ge+1; j--)//倒着整
res+=x-b[j];//把差的加起来
ans=min(ans,res);//取min
}
printf("%lld\n",ans);//long long
return 0;
}

浙公网安备 33010602011771号