Small data n,m<=N<=1000,p<=1000
Big data n,m<=N<=100000,p<=100000
sample input
Euler function:
The Euler function represents the number of x that satisfies 1<=x<=n and is relatively prime to n.
Using Euler's function , we can reason as follows:
because ,
So x,n divided by i are relatively prime:
Therefore, the following is a key thinking transformation. When n and i are determined, the number of numbers that are relatively prime (and smaller) to n/i can be obtained , and this number is multiplied by i to obtain a corresponding x
Assuming that the number of possible values of x satisfying the formula gcd(x,n) = i can be expressed as g(i,n), then:
That is, given the remainder and n, we can get the number of x that satisfies gcd(x, n) = i. For the rest, we only need to count the number of different gcd values to calculate the required sum.
specific algorithm
The Euler function can be listed first. See the code for how to type.
Might as well set n<=m, we count the possible values of gcd within the range, just let
Among them, phi is the Euler function table, and f(i, j) represents the number of pairs where gcd is i, and n is j. When i=j, it is calculated once more, so 1 must be subtracted.
code show as below:
#include<iostream> #include<vector> #include<time.h> #include<stdlib.h> #include<stdio.h> #include<string.h> #include<math.h> using namespace std; int phi[100100];int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b); } void phi_table(int n) { memset(phi, 0, sizeof(phi)); phi[1] = 1; for (int i = 2; i <= n; i++) { if (!phi[i]) { for (int j = i; j <= n; j += i) { if (!phi[j]) phi[j] = j; phi[j] = phi[j] / i * (i - 1 ); } } } } int main() { int N, n, m, p; while (cin >> N >> n >> m >> p) { phi_table(N); vector<int> E(N + 1); E[1] = p; memset(a, 0, sizeof(a)); long long sum = 0; for (int i = 2; i <= N; i++) { E[i] = (E[i - 1] + 153) % p; } if (n > m) { int t = n; n = m; m = t; } for (int i = 1; i <= n; i++) { // 遍历gcd(a, b) 的可能取值 1<=i<=n for (int j = i; j <= m; j += i) { if (j <= n) { int r = phi[j / i] + phi[j / i]; // printf("sum += %d %d %d %d\n", i, j, j / i, r); sum += r * E[i]; } else { int r = phi[j / i]; // printf("sum += %d %d %d %d\n", i, j, j / i, r); sum += r * E[i]; } } sum - = E [i]; } // DEBUG() // int sum2 = 0; // int* hit = new int[m + 1]; // memset(hit, 0, sizeof(int) * (m + 1)); // for (int i = 1; i <= n; i++) { // for (int j = 1; j <= m; j++) { // int dv = gcd(i, j); // sum2 += E[dv]; // hit[dv]++; // } // } // for (int i = 1; i <= n; i++) { // printf("gcd = %d %d\n", i, hit[i]); // } // delete [] hit; // cout << sum2 << endl; // END_DEBUG() cout << sum << endl; } return 0; }
test case
enter:
20 3 4 10
10 3 3 10
100000 100000 100000 10
10 1 1 10
output:
102
79
78421508982
10
references
[1]UVa 11426 - GCD - Extreme (II) https://blog.sengxian.com/solutions/uva-11426