P3172 [CQOI2015] + number of selected memory content search repellent

P3172 [CQOI2015] Number selected from

label

  • Inclusion-exclusion
  • Memory search

Foreword

  • Good question - can teach after inversion Du screen, you can then push the formula dp! !

Concise meaning of the questions

  • Given \ (n-, K, L, R & lt \) , you need to obtain, from the request interval \ ([L, R] \ ) is selected in \ (n-\) number and their \ (gcd = k \ ) the number of programs. (Repeat number selected)

Thinking

  • We assume that a set of sample, \ (= n-2, K =. 3, L = 2, 10 = R & lt \) . So we need from \ ([2,10] \) to select two numbers, making their \ (gcd = 2 \) . One obvious thing is that no matter how we choose, choose a certain number of these are \ (k \) multiples.
  • We found that we assume that the sample, k = 3,6,9 are multiples of 3, the number is assumed to be \ (X \) , where \ (X = 3 \) . So we list all options, a total of \ (x ^ n = 3 ^ 2 = 9 \) kinds of programs are: (3,3), (3,6), (3,9), (6 , 3), (6,6), (6,9), (9,3), (9,6), (9,9). Obviously, there are some \ (gcd \) apparently 3, there are some 6, some even 9.
  • Now set \ (f (i) \) for a given \ (n-, K, L, R & lt \) , to choose the \ (n-\) number and (gcd = i \) \ number of programs. Still according to the above examples, \ (F (2) = ^ 2. 3-F (. 6) -f (. 9) \) (wondering about how this equation come). So order \ (x = [L, R ] \) in \ (I \) number multiple of, in accordance with the above examples, it is easy to know
    \ [f (i) = x ^ nf (2 * i) -f (3 * i) -...- f (m * i) (m * i <= R) \]

    Here to talk about the method for finding x. \ (X = \ FRAC Ri- \ FRAC-L {I}. 1 \) . how this formula may be exemplified as to know their

  • This is a recursive, obviously, when the \ (k = 1, R = 1e9 \) , the recursion constant T. It was optimized. Breakthrough is optimized sentence: \ (of HL <= 10. 5 ^ \) . Then we have an important property: from \ ([l, r] \ ) selected several different numbers, they \ (gcd \) does not exceed \ (RL \) . Know the nature of our \ (f (x) \) can not have the \ (f (2 * i) \) have been taken into account \ (f (m * i) (m * i <= R) \) , because \ (m * i \) simply can not be \ (GCD \) , so that only the \ (f (2 * i) \) taking into account the \ (f (m * i) (m * i <= RL ) \) , but it needs a little change.
  • Memories \ (f (i) \) is defined, which contains the same number of case of selecting. So we only choose to calculate the number of different situations, so you can use the above said \ (gcd \) character, simply select the number of the last subtract the same number of programs. However a lot of trouble, the number is the same protocol set p, when n = 1, p is 0 obviously, when n> = 2, we need to consider multiple of [L, R] of the interval k, and combinations mathematical calculations. A lot of trouble. There is a simplified method:
  • Is directly to the L, R divided by k, then it becomes to find gcd == 1, the number of programs in the new section in. After this, the number of elements of the protocol is repeated calculations is very good, because k = 1, and only a prime number 1, so the elements can only be repeated 1, L = 1 as long as the new and to choose the number of 2 or more, then the program number to +1, it's that simple.

Precautions

  • Direct subtraction modulo go wrong, we should add another module modulo

to sum up

  • From \ ([l, r] \ ) select a plurality of different numbers, their \ (GCD \) does not exceed \ (RL \)

AC Code

#include <cstdio>
#include <unordered_map>
using namespace std;

const int mod = 1000000007;

int ksm(int a, int b) {
    int base = a, ans = 1;
    while (b) {
        if (b & 1)
            ans = 1ll * ans * base % mod;
        base = 1ll * base * base % mod;
        b >>= 1;
    }
    return ans;
}

int n, k, l, r;
unordered_map<int, int> rec;

int f(int k) {
    if (rec[k] != 0)
        return rec[k];
    int x = r / k - (l - 1) / k;
    int ans = ksm(x, n) - x;

    for (int i = 2; i * k <= r - l; i++) ans = (ans - f(i * k) + mod) % mod;

    return rec[k] = ans;
}

void solve() {
    scanf("%d%d%d%d", &n, &k, &l, &r);
    l = (l % k == 0 ? l / k : l / k + 1);
    r /= k;
    k = 1;

    printf("%d", f(k) + (l == 1 && n >= 2));
}

int main() {
    solve();
    return 0;
}

Guess you like

Origin www.cnblogs.com/danzh/p/11299393.html
Recommended