反演+積性函式--CF757E Bash Plays with Functions
阿新 • • 發佈:2018-12-13
可以很容易推到
f_r(n) = sigema (d|n) f_r-1(d)
f_0(n) = 2^(n的質因子個數)
然後就不知道怎麼辦了
這是一個積性函式的應用小技巧
看出來f_0是一個積性函式,那麼f_r也是積性函式
證明積性函式可以把表示式拆成關於質因子的多少次冪的式子,如果各個質因子互相獨立就是積性函式
知道是積性函式後我們只需要考慮根基也就是f_r( p^t ) 時候的取值,我們可以預處理
然後觀察式子,這個式子右邊就相當於f_r-1 * 1 (n) *表示卷積
推一推式子可以發現,設f[i][j]表示f_i(p^j)
那麼f[i][j]=sigema (k=0 to j) f[i-1][k]
字首和優化即可
每次詢問的時候暴力把n分解質因數再乘上相應答案
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define LL long long #define maxn 1000001 #define maxm 22 using namespace std; int q,r,n,minp[maxn],pri[maxn],cnt; int f[maxn][maxm],sum[maxn][maxm]; bool vis[maxn]; const int mod=1e9+7; inline int rd(){ int x=0,f=1;char c=' '; while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar(); while(c<='9' && c>='0') x=x*10+c-'0',c=getchar(); return x*f; } inline void pre(){ for(int i=2;i<maxn;i++){ if(!vis[i]) pri[++cnt]=i,minp[i]=i; for(int j=1;j<=cnt && i*pri[j]<maxn;j++){ vis[i*pri[j]]=1; minp[i*pri[j]]=pri[j];//每個數的最小質因子 if(i%pri[j]==0) break; } } } int main(){ q=rd(); pre(); f[0][0]=sum[0][0]=1;//n=1特殊考慮 for(int i=1;i<maxm;i++) f[0][i]=2,sum[0][i]=sum[0][i-1]+f[0][i];//字首和優化 for(int i=1;i<maxn;i++){ for(int j=0;j<maxm;j++) f[i][j]=sum[i-1][j]; sum[i][0]=f[i][0]; for(int j=1;j<maxm;j++) sum[i][j]=(sum[i][j-1]+f[i][j])%mod; } while(q--){ r=rd(); n=rd(); LL ans=1; while(n>1){ int t=minp[n],j=0;//每次把最小的素數拆出來 while(n%t==0) n/=t,j++; (ans*=f[r][j])%=mod; } printf("%lld\n",ans); } return 0; }