1. 程式人生 > 實用技巧 >HDU 4135 Co-prime(容斥原理)

HDU 4135 Co-prime(容斥原理)

題目連結

題目大意

  求區間內與n互質的數的數量。

解題思路

  對於區間顯然用[b,1]-[1,a-1]的結果就行了。反過來想,從原來的數中刪去與n不互質的數。將n分解質因數,然後利用容斥原理去掉與n有公因數的數即可。
  假設分解質因數的結果是2,3,5,觀察發現結果就是去掉能被2,3,5整除的數,加上能被2和3,2和5,3和5整除的數,加上能被2和3和5整除的數,當去掉的數是一個奇數項時是減號,偶數項時時加號。同時,每新加入一個質因子,就是在前面的結果上都乘上這個質因子(假設第一個數是1)。

程式碼

const int maxn = 1e5+10;
const int maxm = 2e2+10;
int p[maxn], u[maxn], q[maxn] = {-1}, __q, k;
vector<int> tmp;
ll solve(ll k, ll x) {
    for (int i = 1; (ll)p[i]*p[i]<=x; ++i)
        if (x%p[i]==0) {
            while(x%p[i]==0) x/=p[i];
            tmp.push_back(p[i]);
        }
    if (x>1) tmp.push_back(x);
    ll res = k; __q = 1;
    for (auto num : tmp) {
        int t = __q;
        for (int i = 0; i<t; ++i) q[__q++] = -q[i]*num;
    }
    for (int i = 1; i<__q; ++i) res -= k/q[i];
    tmp.clear();
    return res;
}
int main() {
    for (int i = 2; i<maxn; ++i) {
        if (!u[i]) u[i] = p[++p[0]] = i;
        for (int j = 1; i*p[j]<maxn; ++j) {
            u[i*p[j]] = p[j];
            if (i%p[j]==0) break;
        }
    }
    int t; scanf("%d", &t);
    while(t--) {
		ll a, b, c; scanf("%lld%lld%lld", &a, &b, &c);
        printf("Case #%d: %lld\n", ++k, solve(b, c)-solve(a-1, c));
    }
    return 0;
}