【BZOJ 2721】 2721: [Violet 5]樱花 (筛)
2721: [Violet 5]樱花
Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 599 Solved: 354Description
Input
Output
Sample Input
Sample Output
HINT
Source
【分析】
之前推出来然后几天直接打然后把$n!^2$的约数记成$n^2$的约数也是醉、、
先通分。
则$(x+y)*n!=x*y$
设$g=gcd(x,y)$
则$(x'+y')*n!=x'*y'*g$
显然$gcd(x'+y',x')=gcd(x'+y',y')=1$
所以$x'*y'|n!$ 、$(x'+y')|g$
设$g=k(x'+y')$,则$n!=x'*y'*k$
枚举$n!$的互质约数对$(x',y')$,则k就确定了,所以只是问$n!$的互质约数对的个数。
把$n!$分解质因数,假设$n!=p1^{r1}+p2^{r2}+...+pn^{rn}$
$f[i]$表示前i个p对答案的贡献,则$f[i]=f[i-1]*(2*ri+1)$
则答案就等于$\Pi (2*ri+1)$,也就是$(n!)^{2}$的约数个数。【别人好像直接推出这个。。。?
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<vector> 7 using namespace std; 8 #define Maxn 1000010 9 #define Mod 1000000007 10 #define LL long long 11 12 int n; 13 int pri[Maxn],pl,mn[Maxn]; 14 bool vis[Maxn]; 15 void init() 16 { 17 memset(vis,0,sizeof(vis)); 18 for(int i=2;i<=n;i++) 19 { 20 if(!vis[i]) pri[++pl]=i,mn[i]=i; 21 for(int j=1;j<=pl;j++) 22 { 23 if(i*pri[j]>n) break; 24 vis[i*pri[j]]=1; 25 mn[i*pri[j]]=pri[j]; 26 if(i%pri[j]==0) break; 27 } 28 } 29 } 30 31 int sm[Maxn]; 32 void cal(int x) 33 { 34 if(x==1) return; 35 sm[mn[x]]++; 36 cal(x/mn[x]); 37 } 38 39 int main() 40 { 41 int ans=1; 42 scanf("%d",&n); 43 init(); 44 memset(sm,0,sizeof(sm)); 45 for(int i=1;i<=n;i++) cal(i); 46 for(int i=2;i<=n;i++) if(sm[i]) ans=1LL*ans*(2*sm[i]+1)%Mod; 47 printf("%d\n",ans); 48 return 0; 49 }
2017-04-24 14:22:56