CF585E Present for Vitalik the Philatelist
比较套路的约数容斥,但是好像还有复杂度更优的做法吧
首先求\(\gcd(S)\ne 1\and \gcd(S,x)=1\)可以转化为\(\gcd(S,x)=1\)的个数减去\(\gcd(S)=1\)的个数
套路地考虑约数容斥,即设\(f_i\)表示\(i|\gcd(S,x)\)的个数,设\(g_i\)表示\(i|\gcd(S)\)的个数
考虑统计出\(c_i\)表示\(i\)的倍数的个数,考虑计算\(f_i\)和\(g_i\):
\[f_i=c_i\times (2^{c_i-1}-1)\\g_i=\sum_{j=1}^{c_i} C_{c_i}^j\times (n-j)\\=n\times \sum_{j=1}^{c_i} C_{c_i}^j-\sum_{j=1}^{c_i}C_{c_i}^j\times j\\=n\times (2^{c_i}-1)-c_i\times \sum_{j=1}^{c_i} \frac{(c_i-1)!}{(j-1)!(c_i-j)!}\\=n\times (2^{c_i}-1)-c_i\times 2^{c_i-1}
\]
然后直接从大到小枚举每个\(i\),设\(f'_i\)表示\(\gcd(S,x)=i\)的个数,\(f'_i=f_i-\sum_{i|j} f'_j\),对于\(g\)同理
最后的答案就是\(f'_1-g'_1\),总复杂度\(O(|a_i|\ln |a_i|)\)
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int S=1e7+5,mod=1e9+7;
int n,x,c[S],f[S],g[S],mx;
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline int sub(CI x,CI y)
{
return x-y<0?x-y+mod:x-y;
}
int main()
{
RI i,j; for (scanf("%d",&n),i=1;i<=n;++i)
scanf("%d",&x),mx=max(mx,x),++c[x];
for (i=1;i<=mx;++i) for (j=i<<1;j<=mx;j+=i) c[i]+=c[j];
for (i=1;i<=mx;++i) if (c[i]) f[i]=1LL*c[i]*sub(quick_pow(2,c[i]-1),1)%mod;
for (i=1;i<=mx;++i) if (c[i]) g[i]=sub(1LL*n*sub(quick_pow(2,c[i]),1)%mod,1LL*c[i]*quick_pow(2,c[i]-1)%mod);
for (i=mx;i;--i) for (j=i<<1;j<=mx;j+=i) f[i]=sub(f[i],f[j]),g[i]=sub(g[i],g[j]);
return printf("%d",sub(f[1],g[1])),0;
}
辣鸡老年选手AFO在即