【BZOJ 4816】数字表(SDOI 2017)-モビウス反転+数論ブロック

6740 ワード

テストアドレス:数値表の作り方:本題はモビウスの反転+数論ブロックを使用する必要があります.本題では,ans=∏ni=1∏mj=1 f(gcd(i,j))a n n s=∏i=1 n∏j=1 m f(gcd(i,j))n#include using namespace std; typedef long long ll; const ll mod=1000000007; int T; ll n[1010],m[1010],maxn,f[1000010],inv[1000010]; ll mu[1000010],prime[1000010],F[1000010],Finv[1000010],prod[1000010],prodinv[1000010]; bool vis[1000010]={0}; void calc_mu() { mu[1]=1; prime[0]=0; for(ll i=2;i<=maxn;i++) { if (!vis[i]) { prime[++prime[0]]=i; mu[i]=-1; } for(ll j=1;j<=prime[0]&&i*prime[j]<=maxn;j++) { vis[i*prime[j]]=1; if (i%prime[j]==0) { mu[i*prime[j]]=0; break; } mu[i*prime[j]]=-mu[i]; } } } ll power(ll a,ll b) { ll s=1,ss=a; while(b) { if (b&1) s=s*ss%mod; ss=ss*ss%mod;b>>=1; } return s; } void init() { scanf("%d",&T); maxn=0; for(int i=1;i<=T;i++) { scanf("%lld%lld",&n[i],&m[i]); if (n[i]>m[i]) swap(n[i],m[i]); maxn=max(maxn,n[i]); } calc_mu(); f[0]=0,f[1]=1; inv[1]=1; for(ll i=2;i<=maxn;i++) { f[i]=(f[i-2]+f[i-1])%mod; inv[i]=power(f[i],mod-2); } for(ll i=1;i<=maxn;i++) F[i]=Finv[i]=1; prod[0]=prodinv[0]=1; for(ll i=1;i<=maxn;i++) { for(ll j=1;i*j<=maxn;j++) { if (mu[j]==1) F[i*j]=F[i*j]*f[i]%mod,Finv[i*j]=Finv[i*j]*inv[i]%mod; if (mu[j]==-1) F[i*j]=F[i*j]*inv[i]%mod,Finv[i*j]=Finv[i*j]*f[i]%mod; } prod[i]=prod[i-1]*F[i]%mod; prodinv[i]=prodinv[i-1]*Finv[i]%mod; } } void work() { for(int i=1;i<=T;i++) { ll ans=1; for(ll j=n[i];j>=1;j=max(n[i]/(n[i]/j+1),m[i]/(m[i]/j+1))) { ll l=max(n[i]/(n[i]/j+1),m[i]/(m[i]/j+1))+1,r=j; ans=ans*power(prod[r]*prodinv[l-1]%mod,(n[i]/j)*(m[i]/j))%mod; } printf("%lld
"
,ans); } } int main() { init(); work(); return 0; }