[Meituan Written Exam] 2018-4-20 Programming Question - Euler Function to Solve gcd

Time limit: 1000MS for C/C++ language; 3000MS for other languages
Memory limit: C/C++ language 65536KB; other languages ​​589824KB
Topic description:
Give you the A array, ask ΣΣA[gcd(i,j)], 1<=i<=n, 1<=j<=m
enter
There are four integers in each row, N, n, m, p, where N represents the length of the A array, and n, m, and p are parameters; for the A array, it is obtained as follows:
  A[1]=p,A[x]=(A[x-1]+153)%p
data range

Small data n,m<=N<=1000,p<=1000

Big data  n,m<=N<=100000,p<=100000

 

output
output answer

sample input

10 1 2 10
Sample output
20 
 
Hint
input example 2
10 2 2 10
Sample output 2
33

 

Example explanation
The array A generated by the first set of examples is: 10 3 6 9 2 5 8 1 4 7. The final output answer is: A[gcd(1,1)] + A[gcd(1,2)] = A[1] + A[1] = 20.
The array A generated by the second set of samples is: 10 3 6 9 2 5 8 1 4 7. The final output answer is: A[gcd(1,1)] + A[gcd(1,2)] + A[gcd(2,1)] + A[gcd(2,2)] = A[1] + A[1] + A[1] + A[2] = 33.
 
 
answer
  The problem gives a rule-generated array and requires you to use the greatest common divisor gcd(i, j) of the paired numbers (i, j) as subscripts to calculate the sum.
  Obviously, naive's approach is to generate the array directly, and then traverse to get the sum. The complexity of this is O(NM) -- only 90% of the time. Obviously in the maximum case 10^5 * 10^5 times out, at least 100s.
A similar topic uva 11426 can be found   from ΣΣA[gcd(i,j)] , the title requirements are:

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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325705646&siteId=291194637