bzoj2721 [Violet 5]樱花(数学+筛法)

题意:

  求方程 1/x + 1/y = 1/n! 的正整数解 (x,y) 的数目。
 
输入格式:一行,一个数N。
 
输出格式:一行,一个数M,解的数目。
 
样例输入:
2
 
样例输出:
3 (分别为(3,6),(4,4),(6,3)).
 
解析:十分小清新的题面。推式子便可得出。
推式子的过程不难理解。
 1/x + 1/y = 1/n! ,为了便于理解,设 1/n! = a.
则原式可化为 1/x + 1/y = 1/a.
将 1/y 移到右边,得 1/x = 1/a - 1/y.
两边各变为原来的倒数,得 x = ay/(y-a).
再设 y - a = d,则 y = a + d.
将 y - a = d, y = a + d 代入得, x = a (a + d) / d.
化简得 x = a^2/d + a.
因为 x 为正整数,所以 d | a^2, 即 d | (n!)^2.
到了这里,只要 (y - a) 为 (n!)^2 时便有解,所以只要得出 (n!)^2 的因子个数便是答案。
 
代码如下:
 1 #include<cstdio>
 2 #define MOD 1000000007
 3 #define maxn 1000001
 4 using namespace std;
 5 
 6 int n,vis[maxn],prime[maxn],tot,bt[maxn];
 7 long long ans=1;
 8 
 9 void euler(void){ //欧拉筛筛出素数 
10     vis[1]=1;
11       for (int i=2;i<=n;++i) {
12           if (!vis[i]) prime[++tot]=i;
13           for (int j=1;j<=tot;++j) {
14               if (prime[j]*i>n) break;
15               vis[prime[j]*i]=1;
16           }
17       }
18 }
19 
20 int main() {
21     scanf("%d",&n);
22     euler();
23       for (int i=2;i<=n;++i) {
24           int x=i;
25           for (int j=1;j<=tot;++j) {  //分解质因数 
26               if (prime[j]>x) break; //素数太大便退出 
27               if (!vis[x]) {      //如果x本身就是素数,直接统计 
28                   bt[x]+=2; break; //bt记录每个素数的出现次数 
29               }                  //由于x与y的值可以互换,故加2 
30               if (x%prime[j]==0) {
31                   int res=0;
32                   while (x%prime[j]==0) {
33                       x/=prime[j];
34                       res++;
35                   }
36                 bt[prime[j]]+=res*2; //同理,x与y可调换,故乘2 
37               }
38           }
39       }
40       for (int i=1;i<=maxn;++i) //计算因数的个数 
41         if (bt[i]) ans=(ans*(bt[i]+1))%MOD;
42     printf("%lld",ans);
43     return 0;
44 }

 (不会用markdown,公式就将就着看看吧)

posted @ 2018-08-19 23:05  Gax_c  阅读(223)  评论(0编辑  收藏  举报