【BZOJ 2721】 2721: [Violet 5]樱花 (筛)

2721: [Violet 5]樱花

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 599  Solved: 354

Description

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 }
View Code

 

 

2017-04-24 14:22:56

posted @ 2017-04-23 22:09  konjak魔芋  阅读(312)  评论(0编辑  收藏  举报