zoukankan      html  css  js  c++  java
  • [hdu1695] GCD ——欧拉函数+容斥原理

    题目

    给定两个区间[1, b], [1, d],统计数对的个数(x, y)满足:

    1. (x in [1, b]), (y in [1, d]) ;
    2. (gcd(x, y) = k)
      HDU1695

    题解

    我们观察式子(gcd(x,y)=k)
    很显然,(gcd(x/k, y/k) = 1)
    我们令b < d,令x<y(避免重复计数)
    分类讨论。

    1. y < b
      可以看出答案就是(sum_{i in [1, b]} phi(i))
      2)(y in [b, d])
      可以看出答案就是calc(b, i),calc函数就是在区间[1,b]中与i互素的个数。

    怎么计算calc函数呢?
    首先我们计算出i的因数,运用容斥原理。

    [| overline{A_1} cap overline {A_2} ... cap overline{A_n}| = | S | - |A_1| - |A_2| ... + |A_1 cap A_2| .... ]

    具体计算见代码。

    代码

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn = 100000;
    int prime[maxn+5], phi[maxn+5], check[maxn+5];
    int T, a, b, c, d, k;
    int cnt = 0;
    void get_phi(int n) {
        memset(check, 0, sizeof(check));
        cnt = 0;
        phi[1] = 1; 
        for(int i = 2; i <= n; i++) {
            if(!check[i]) {
               phi[i] = i-1;
               prime[cnt++] = i;
            }
            for(int j = 0; j < cnt; j++) {
                if(i * prime[j] > n) break;
                check[i*prime[j]] = 1;
                if(i % prime[j] == 0) {
                    phi[i * prime[j]] = phi[i] * prime[j];
                    break;
                } else {
                    phi[i * prime[j]] = phi[i] * (prime[j] - 1);
                }
            }
        }
    }
    ll factor[maxn];
    int ct = 0;
    void get_factor(int x) {
        ct = 0;
        ll tmp = x;
        for(int i = 0; prime[i] * prime[i] <= x; i++) {
            if(tmp % prime[i] == 0) {
                factor[ct] = prime[i];
                while(tmp % prime[i] == 0) {
                    tmp /= prime[i];
                }
                ct++;
            }
        }
        if(tmp != 1) 
            factor[ct++] = tmp;
       
    } 
    
    int calc(int n, int m) {
        get_factor(m);
        int ans = 0;
        for(int i = 1; i < (1 << ct); i++) {
            int cnt = 0;
            int tmp = 1;
            for(int j = 0; j < ct; j++) {
                if(i & (1 << j)) {
                    cnt++;
                    tmp *= factor[j];
                }
            }
            if(cnt & 1) ans += n / tmp;
            else ans -= n/tmp;
        }
        return n - ans;
    }
    
    int main() {
        //freopen("input", "r", stdin);
        scanf("%d", &T);
        get_phi(maxn);
        int kase = 0;
        while(T--) {
            kase++;
            scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);
            if((k == 0) | (k > b) | (k > d)) {
                printf("Case %d: 0
    ", kase);
                continue;
            }
            if(b > d) swap(b, d);
            b /= k;
            d /= k;
            ll ans = 0;
            for(int i = 1; i <= b; i++) ans += phi[i];
            for(int i = b+1; i <= d; i++)
                ans += calc(b, i);
            printf("Case %d: %lld
    ", kase, ans);
        }
        return 0;
    }
    
  • 相关阅读:
    实现Echarts折线图的虚实转换
    解决Webpack 安装sass时出现的错误
    Videojs视频插件在React中的应用
    overflow应用场景
    【JS Note】字符串截取
    【JS Note】undefined与null
    Web 网页常见问题集锦
    微信内置浏览器中,点击下拉框出现页面乱跳转现象(iphone)
    input美化 checkbox和radio样式
    Discuz!图片查看插件(支持鼠标缩放、实际大小、旋转、下载)
  • 原文地址:https://www.cnblogs.com/gengchen/p/6360590.html
Copyright © 2011-2022 走看看