题面
给定 n,k,求:
i1=1∏ni2=1∏n⋯ik=1∏nφ(lcm(i1,i2,⋯,ik))
对 109+7 取模。n,k≤106。
题解
不妨设集合 S={i1,i2,⋯,ik}。下面我们类比 min-max 容斥给出一个式子:
对于任意积性函数 f,有:
f(lcm(x∣x∈S))=T⊆S∏f(gcd(x∣x∈T)(−1)∣T∣+1)
这个式子取 f=id 就有了朴素的 gcd-lcm 容斥。
将原式转化成这个形式:
S∏T⊆S∏φ(gcd(T))(−1)∣T∣+1
枚举 T 的大小:
j=1∏k⎝⎜⎛i1∏ni2∏n⋯ij∏nφ(gcd(i1,i2,⋯,ij))⎠⎟⎞(−1)j+1nk−j(jk)
括号里的一车东西是一个反演:
d=1∏nφ(d)∑t=1n/dμ(t)⌊dtn⌋k
这个东西可以考虑把指数拿下来:
t=1∏n⎝⎜⎛d∣t∏φ(d)μ(dt)⎠⎟⎞⌊tn⌋k
括号里的东西可以写筛子预处理。将其记为 f(t)。回头代入原式整理一下可以得到:
t=1∏nf(t)−∑j=1k⌊tn⌋j(−1)jnk−j(jk)
指数的依托答辩是二项式定理,得到最终式:
t=1∏nf(t)nk−(n−⌊tn⌋)k
可以 nlogn 解决。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| #include<bits/stdc++.h> #define int long long using namespace std; const int max_n=1000006,mod=1000000007; inline int read(){ int x=0;bool w=0;char c=getchar(); while(c<'0' || c>'9') w|=c=='-',c=getchar(); while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return w?-x:x; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10^48); } inline int mi(int a,int p=mod-2){ int res=1; if(p<0) return mi(mi(a),-p); while(p){ if(p&1) res*=a,res%=mod; a*=a,a%=mod,p>>=1; } return res; } inline int mi2(int a,int p){ int mod=1000000006,res=1; while(p){ if(p&1) res*=a,res%=mod; a*=a,a%=mod,p>>=1; } return res; }
bool isp[max_n]; int cntp,pr[max_n/10],phi[max_n],mu[max_n];
int f[max_n],ivp[max_n];
inline void GetPr(int n){ memset(isp,1,sizeof(isp)),isp[1]=0; phi[1]=mu[1]=1; for(register int i=2;i<=n;++i){ if(isp[i]){ pr[++cntp]=i; phi[i]=i-1,mu[i]=-1; } for(register int j=1;j<=cntp && i*pr[j]<=n;++j){ isp[i*pr[j]]=0; if(i%pr[j]==0){ phi[i*pr[j]]=phi[i]*pr[j], mu[i*pr[j]]=0; break; } phi[i*pr[j]]=phi[i]*phi[pr[j]], mu[i*pr[j]]=-mu[i]; } } for(register int i=1;i<=n;++i) ivp[i]=mi(phi[i]); for(register int i=1;i<=n;++i) f[i]=1; for(register int i=1;i<=n;++i) for(register int j=i,k=1;j<=n;j+=i,++k) if(mu[k]) f[j]=f[j]*(mu[k]==1?phi[i]:ivp[i])%mod; }
int n,K,ans=1;
int pw[max_n];
signed main(){ GetPr(1000000); n=read(),K=read(); for(register int i=0;i<=n;++i) pw[i]=mi2(i,K); for(register int t=1;t<=n;++t) ans=ans*mi(f[t],pw[n]-pw[n-n/t])%mod; write(ans); return 0; }
|