JZOJ 3158. 【JSOI2013】丢番图
Time Limits: 1000 ms Memory Limits: 65536 KB Detailed Limits
题目
Description
丢番图是亚历山大时期埃及著名的数学家。他是最早研究整数系数不定方程的数学家之一。
为了纪念他,这些方程一般被称作丢番图方程。最著名的丢番图方程之一是 x n + y n = z n x^n+y^n=z^n xn+yn=zn。费马
提出,对于 n ≥ 2 n≥2 n≥2, x n + y n = z n x^n+y^n=z^n xn+yn=zn没有正整数解。这被称为“费马大定理”,它的证明直到最近才被安德鲁·怀尔斯(Andrew Wiles)证明。
考虑如下的丢番图方程: 1 / x + 1 / y = 1 / n ( x , y , n ∈ N ∗ ) 1/x+1/y=1/n(x,y,n∈N*) 1/x+1/y=1/n(x,y,n∈N∗)
小G对下面这个问题十分感兴趣:对于一个给定的正整数 n n n,有多少种本质不同的解满足方
程?例如 n = 4 n=4 n=4,有三种本质不同 ( x ≤ y ) (x≤y) (x≤y)的解:
1 / 5 + 1 / 20 = 1 / 4 1/5+1/20=1/4 1/5+1/20=1/4
1 / 6 + 1 / 12 = 1 / 4 1/6+1/12=1/4 1/6+1/12=1/4
1 / 8 + 1 / 8 = 1 / 4 1/8+1/8=1/4 1/8+1/8=1/4
Input
显然,对于更大的 n n n,没有意义去列举所有本质不同的解。你能否帮助小G快速地求出对于给定 n n n,满足方程的本质不同的解的个数?
Output
一行,仅一个整数 n ( 1 ≤ n ≤ 1 0 14 ) n(1≤n≤10^{14}) n(1≤n≤1014)。
Sample Input
4
Sample Output
3
Data Constraint
对于30%的数据,
n
≤
1
0
5
n≤10^5
n≤105.
对于50%的数据,
n
≤
2
31
n≤2^{31}
n≤231.
对于100%的数据,
n
≤
1
0
14
n≤10^{14}
n≤1014.
题解
- 首先可以确定 x , y x,y x,y的范围, x , y ∈ [ n + 1 , 2 n ] x,yin[n+1,2n] x,y∈[n+1,2n],这是十分显然的!
- 一种暴力做法,枚举 x x x,判断是否有可行的 y y y,
- 1 x + 1 y = 1 n frac 1 x+frac 1y=frac1n x1+y1=n1
- < = > 1 y = x − n n x <=>frac 1y=frac{x-n}{nx} <=>y1=nxx−n
- < = > y = n x x − n <=>y=frac{nx}{x-n} <=>y=x−nnx
- 枚举完后判断 x − n x-n x−n是否是 n x nx nx的约数即可。
- 但这样时间是很慢的,不妨再来推一波式子:
- 由上面得:
- y = n x x − n y=frac{nx}{x-n} y=x−nnx
- < = > y ( x − n ) = n x <=>y(x-n)=nx <=>y(x−n)=nx
- 同理可得,
- x ( y − n ) = n y x(y-n)=ny x(y−n)=ny
- 两式相乘,得
- x y ( x − n ) ( y − n ) = n 2 x y xy(x-n)(y-n)=n^2xy xy(x−n)(y−n)=n2xy
- < = > ( x − n ) ( y − n ) = n 2 <=>(x-n)(y-n)=n^2 <=>(x−n)(y−n)=n2
- 这样方案数就是 n 2 n^2 n2的约数个数……吗?
- 当然不是,因为要求 x ≤ y x≤y x≤y所以答案要除以 2 2 2,
- 但 n 2 n^2 n2的约数中必然是有 n n n的,这里不会有重复多余的一组答案,
- 所以最终的答案先加 1 1 1再除以 2 2 2。
- 怎么求 n 2 n^2 n2约数个数?
- 显然是分解质因数,但当然不用分解 n 2 n^2 n2,
- 分解 n n n就好了,质因数个数全部乘 2 2 2就是 n 2 n^2 n2的每个质因数个数了!
- 全部加 1 1 1相乘即可得到 n 2 n^2 n2约数个数(小学奥数)。。。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define LL long long
int a[1000010],p[10000010],f[1000010];
int main()
{
LL n,t;
int i,j,s=0;
scanf("%lld",&n);
t=floor(sqrt(n));
for(i=2;i<=t;i++) if(!p[i])
{
p[i]=1;
a[++s]=i;
for(j=2;j<=t/i;j++) p[i*j]=1;
}
int k=1;
while(n>1&&k<=s)
{
while(n%a[k]==0)
{
n/=a[k];
f[k]++;
}
k++;
}
LL ans;
if(n>1) ans=3; else ans=1;
for(i=1;i<=s;i++) ans=ans*(f[i]*2+1);
printf("%lld",ans/2+1);
return 0;
}