牛客NOIPtg day5 B-demo的gcd
一句话题意:给定长度为n的序列,求任意两两之间gcd的积mod 998244353的值。
好像是莫比乌斯反演板子题???(反正noip估计不考这种毒瘤
考场上想到一个类似正解的思路 好像摊下来最多处理nlogn次就义无反顾地写了结果爆零
(你以为for while if continue 都不要时间的啊
后来一看发现自己的思路貌似毫无问题,就是实现丑了(逃
可以看到对于每一个质数p,对答案的贡献为p^k(k-1) 其中k=序列中包含质因数p的数个数
然后对于质数的幂次p^q,考场上的思路是每次计算质数之后将原序列中的该质数除掉,如此循环直到找不到该质因数为止(于是就T了还不如暴力qvq
其实可以考虑另一种很简单的思路 对于任意一个p^k,枚举他的倍数,对答案的贡献即为p^k'(k'-1),与上述等价,复杂度为O(nlogn)(其实是ln
代码如下
#include <cstdio> #include <iostream> #define qvq register #define int long long using namespace std; const int mod=998244353; const int maxn=1000005; int p[maxn],cnt,a[maxn]; bool np[maxn]; inline int read() { int x=0,f=1; char cr=getchar(); while (cr>'9' || cr<'0') { if (cr=='-') f=-1; cr=getchar(); } while (cr>='0' && cr<='9') { x=(x<<3)+(x<<1)+cr-'0'; cr=getchar(); } return x*f; } inline void euler() { for (qvq int i=2;i<=1000000;i++) { if (!np[i]) p[++cnt]=i; for (qvq int j=1;j<=cnt && p[j]*i<=1000000;j++) { np[p[j]*i]=1; if (i%p[j]==0) break; } } } inline int val(int k) { return k*(k-1)/2; } inline int power(int a,int b,int p) { if (b==0) return 1; if (b==1) return a; if (b&1) return a*power(a*a%p,b>>1,p)%p; else return power(a*a%p,b>>1,p); } int num[maxn],f[maxn]; signed main() { int n=read(); int lim=-1; for (qvq int i=1;i<=n;i++) a[i]=read(),num[a[i]]++,lim=max(lim,a[i]); euler(); for (int i=1;i<=cnt;i++) { int temp=p[i]; while (temp<=1000000) { f[temp]=p[i]; temp*=p[i]; } } int ans=1; for (int i=1;i<=lim;i++) { if (!f[i]) continue; int res=0; for (int j=i;j<=lim;j+=i) res+=num[j]; ans*=power(f[i],val(res),mod),ans%=mod; } printf("%lld",ans); }
我太菜了orz