voidexgcd(int a, int b, int &x, int &y){ if (b == 0) { a = 1; return; } exgcd(b, a % b, y, x); y -= a / b * x; // Recursive calculation, detailed explanation omitted... } exgcd(a, n, x, y);
It is easy to see that since all other nj are coprime to ni and share no common factors greater than 1 with it, the product of all other nj naturally shares no common factors greater than 1 with ni, thus gcd(mi,Mi)=1
That is, Mi and mi are coprime, so we can use the Extended Euclidean Algorithm to calculate ti, such that tiMi=1(modmi)
Which satisfies the problem conditions
The minimum answer is x, and the solution set is x+km,k∈N
Euler’s Totient Function
First, define Euler’s totient function ϕ(n) as the number of positive integers less than or equal to n that are coprime to n
Next, we prove that Euler’s totient function is multiplicative, i.e., ϕ(nm)=ϕ(n)ϕ(m), which means there is a bijection between ϕ(nm) and ϕ(n)ϕ(m)
First, let n, m be coprime,
For
{N=a(modn)N=b(modm)
First, by the definition of Euler’s totient function, N is a number counted in ϕ(nm), and N is coprime to nm,
Therefore, N is coprime to n and m respectively,
Therefore, the Chinese Remainder Theorem is applicable, as it also happens to require coprimality
From the above, since t1,t2 for a,b are unique, when k is 0, i.e., N\leq mn, N is also unique,
Therefore, the number of N is the product of the number of possible a’s and the number of possible b’s, which is the product of the number of t1’s and t2’s
Q.E.D.
Next, it is easy to see that when n=pk
ϕ(pk)=pk−pk−1=(1−p1)pk=(1−p1)n
So when
n=∏pik
, separating each prime power factor of n
ϕ(n)=∏(pi−1)piki−1=n∏(1−pi1)
Next, we introduce several properties of ϕ(n)
First, let p1 be the smallest prime factor of n, n1p1=n
So we can calculate Euler’s totient function linearly, because the Euler sieve can find the smallest prime factor each time
voidwork(int n){ vector<bool> vis(n + 1); vector<int> phi(n + 1), pri; for (int i = 2; i <= n; i++) { if (!vis[i]) { pri.push_back(i); phi[pri] = pri - 1; } for (auto p : pri) { if (i * p > n) break; vis[i * p] = true; // secondary division if (i % p == 0) { // i->n1, p->p1, phi[i * p] = phi[i] * p; } phi[i * p] = phi[i] * phi[p]; // Multiplicative } } }
So we can give the AC code
#include<bits/stdc++.h> #define mod 666623333 #define int long long #define N 1000001 usingnamespace std;
bitset<N> vis; voidsolve(){ int l, r; cin >> l >> r; vector<int> pri; for (int i = 2; i <= N; i++) { if (!vis[i]) { pri.push_back(i); } for (auto p : pri) { if (i * p > N) break; vis[i * p] = true; // i is no longer suitable as a factor if (i % p == 0) break; } } vector<int> phi(N), minp(N); for (int i = l; i <= r; i++) phi[i - l] = i, minp[i - l] = i; for (int p : pri) { if (p * p > r) break; for (int x = (p - l % p) % p; x <= r - l; x += p) { // Calculate contribution in turn phi[x] = phi[x] / p * (p - 1); while (minp[x] % p == 0) minp[x] /= p; } }
int ans = 0; for (int i = 0; i <= r - l; i++) { if (minp[i] > 1) phi[i] = phi[i] / minp[i] * (minp[i] - 1); ans = (ans + i + l - phi[i]) % mod; } cout << ans << '\n'; }
signedmain(){ ios::sync_with_stdio(false); cin.tie(0); freopen("data.in", "r", stdin); freopen("data.out", "w", stdout); int _ = 1; while (_--) solve(); }