Project Euler 531
题目
Chinese leftovers
Let \(g(a,n,b,m)\) be the smallest
non-negative solution \(x\) to the
system:
\(\begin{aligned} & x = a \bmod n\\
& x = b \bmod m \end{aligned}\)
if such a solution exists, otherwise \(0\).
E.g. \(g(2,4,4,6)=10\), but \(g(3,4,4,6)=0\).
Let \(\varphi(n)\) be Euler’s
totient function.
Let \(f(n,m)=g(\varphi(n),n,\varphi(m),m)\).
Find \(\sum f(n,m)\) for \(1000000 \le n < m < 1005000\).
解决方案
题意比较裸,直接求出欧拉函数值然后通过中国剩余定理求方程的解即可。
当然也可以令\(x=t_an+a=t_bm+b\),那么可以写出方程\(t_an-t_bm=b-a\),只需要用一次扩展欧几里得算法就可以求出\(t_a,t_b\),从而重新计算出\(x\)。这种做法比起使用中国剩余定理,少使用了一次扩展欧几里得算法,故也可以考虑。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| # include <bits/stdc++.h> using namespace std; typedef long long ll; const int L=1000000,R=1005000; int phi[R+4]; ll ex_gcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1;y=0;return a; } ll g=ex_gcd(b,a%b,x,y); ll z=x-(a/b)*y; x=y;y=z;return g; }
ll congruence(ll a,ll c,ll m){ ll x,y,g; g=ex_gcd(a,m,x,y); if(c%g!=0) return -1; x*=c/g; ll t=m/g; return (x%t+t)%t; } ll CRT(ll b,ll m,ll c,ll n){ ll y=congruence(m,c-b,n); if(y==-1) return -1; ll x=m*y+b; ll t=m*n; return (x%t+t)%t; } int main(){ for(int i=1;i<R;i++) phi[i]=i; for(int i=2;i<R;i++){ if(phi[i]!=i) continue; phi[i]=i-1; for(int j=i+i;j<R;j+=i) phi[j]=phi[j]/i*(i-1); } ll ans=0; for(int i=L;i<R;i++){ for(int j=i+1;j<R;j++){ ll x=CRT(phi[i],i,phi[j],j); if(x!=-1) ans+=x; } } printf("%lld\n",ans); }
|