最大公因数(gcd.c/.cpp/.pas)
题目描述
给定正整数n,求。
样例输入
6
样例输出
15
数据范围
对于40%的数据:1<=n<=1000000
对于100%的数据:1<=n<=3*10^12
提示:保证答案不超过10^18
原创题!
……好吧其实最后发现bzoj2705【longge的问题】跟这个一毛一样,但是这个数据更强
不过我真是独立yy出来的
首先,考虑gcd(i,n)==k的i有几个
显然这是等价于gcd(j,n/k)==1的j有几个,其中1<=j<=n/k
看到gcd==1,即j与n/k互质,你想到什么?显然是欧拉函数啊
gcd(j,n/k)==1的j的个数就是phi(n/k),其中每个gcd(i,n)==k对答案的贡献是k,所以总的答案就是Σphi(n/k)*k,1<=k<=n且n%k==0
显然这个式子等价于Σphi(k)*(n/k),1<=k<=n且n%k==0
那么对n分解质因数,然后枚举它的每个因子取了多少个,算phi(k)*(n/k)就近似O(1)了
总复杂度是O(sqrt(n))
(所以完全可以开到10^15的,只是怕爆了long long要高精太麻烦)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<deque> #include<set> #include<map> #include<ctime> #define LL long long #define inf 0x7ffffff #define pa pair<int,int> #define mxprime 1500000 using namespace std; bool mrk[1500010]; LL prime[1000000],a[100]; LL n,wrk,ans; int lenp,len; int b[100],now[100]; inline LL read() { LL x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void getprime() { for (int i=2;i<=mxprime;i++) mrk[i]=1; for (int i=2;i<=mxprime;i++) if (mrk[i]) { prime[++lenp]=(LL)i; for(int j=2*i;j<=mxprime;j+=i)mrk[j]=0; } } inline void dfs(int step) { if (step==len+1) { LL sum=1ll,tot=1ll; for (int i=1;i<=len;i++) { for (int j=1;j<=now[i];j++) sum*=a[i],tot*=a[i]; if (now[i])sum=sum/a[i]*(a[i]-1); } ans+=sum*(n/tot); return; } for(int j=0;j<=b[step];j++) { now[step]=j; dfs(step+1); } } int main() { getprime(); n=wrk=read(); for (int i=1;prime[i]*prime[i]<=wrk;i++) { LL nowp=prime[i]; if (wrk%nowp==0) { a[++len]=nowp; b[len]=1; wrk/=nowp; while (wrk%nowp==0) { b[len]++; wrk/=nowp; } } } if (wrk!=1) { if (wrk==a[len])b[len]++; else { a[++len]=wrk; b[len]=1; } } dfs(1); printf("%lld\n",ans); }