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,公式就将就着看看吧)