2022-8-5 #22 CF653G
前几天都在摆啊,不知不觉就到了 UNR 了。
056 CF653G Move by Prime
容易发现质数之间互不影响,不妨令序列中质数对应幂次分别为 \(x_1,x_2,\cdots,x_n\),我们只需将所有 \(x\) 调整至中位数,考虑每个点的贡献即:排名在严格前一半产生负贡献,排名在严格后一半产生正贡献。
对于排名为 \(i\) 的值,列出式子:
\[F(x)=(1+\frac{1}{x})^{i-1}(1+x)^{n-i}=\frac{(1+x)^{n-1}}{x^{i-1}}
\]
即提取 \(F\) 正次数系数减去负次数系数,得到:
\[\sum_i x_i(\sum_{j=i}^{n-1}{n-1\choose j}-\sum_{j=0}^{i-2}{n-1\choose j})
\]
直接计算即可,复杂度 \(O(n\log n)\)。
做个前缀和,利用埃氏筛可以做到 \(O(n\log \log n)\)。
#include<stdio.h>
const int maxn=300005,mod=1000000007;
int n,ps,ans;
int a[maxn],p[maxn],c[maxn],fac[maxn],nfac[maxn],inv[maxn],sum[maxn],v[maxn],tot[maxn],cnt[maxn];
void sieve(int n){
c[1]=fac[0]=fac[1]=nfac[0]=nfac[1]=inv[1]=1;
for(int i=2;i<=n;i++){
fac[i]=1ll*fac[i-1]*i%mod,inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod,nfac[i]=1ll*nfac[i-1]*inv[i]%mod;
if(c[i]==0)
p[++ps]=i;
for(int j=1;j<=ps&&i*p[j]<=n;j++){
c[i*p[j]]=1;
if(i%p[j]==0)
break;
}
}
}
inline int C(int a,int b){
return a<b? 0:1ll*fac[a]*nfac[b]%mod*nfac[a-b]%mod;
}
int main(){
sieve(300000),scanf("%d",&n);
for(int i=1,x;i<=n;i++)
scanf("%d",&x),tot[x]++;
sum[0]=1;
for(int i=1;i<n;i++)
sum[i]=(sum[i-1]+C(n-1,i))%mod;
for(int i=1;i<=n;i++)
v[i]=(0ll+v[i-1]+sum[n-1]-sum[i-1]-(i>=2? sum[i-2]:0)+mod+mod)%mod;
for(int i=1;i<=ps;i++){
int x=p[i],mul=x,c=0;
while(1){
c++,cnt[c]=0;
for(int j=mul;j<=300000;j+=mul)
cnt[c]+=tot[j];
if(cnt[c]==0){
c--;
break;
}
if(1ll*mul*x>300000)
break;
mul*=x;
}
cnt[c+1]=0;
for(int j=1;j<=c;j++)
ans=(ans+1ll*(v[cnt[j]]-v[cnt[j+1]])*j)%mod;
}
printf("%d\n",ans);
return 0;
}