zoukankan      html  css  js  c++  java
  • HDU4135 Co-prime [容斥]

    CoprimeCo-prime


    Descriptionmathcal{Description}
    求区间 L,RL,R 之间与 NN 互质的数的个数 , L,R<=1015,N<=109L,R<=10^{15}, N<=10^9


    最初想法
    NN 分解质因数, 得出 cntcnt 个不同的质因数, 存到 p[]p[] 数组中.
    利用 容斥 计算 [1,x][1,x] 中与NN不互质的数的数量 numnum, 互质的数量则为 xnumx-num.
    使用 [1,L1],[1,R][1,L-1],[1,R] 的答案再 容斥 一下就可以了 .

    AttentionAttention

    • ,N,p[]分解质数到最后时, N可能为最后的大质数, 需要计入p[]
    • 在容斥找 numnum 时需要 求解 LCMLCM, 不能莽乘.
    • DFS容斥时需要 判断是否一个数都没有选.

    DFSDFS 部分:

    void DFS(int k, bool opt, int p_sum, const int &x){
            if(k == cnt+1){
                    if(p_sum == 1) return ;
                    if(!opt) Tmp_1 -= x/p_sum;
                    else Tmp_1 += x/p_sum;
                    return ;
            }
            DFS(k+1, opt^1, Lcm(p_sum, p[k]), x);
            DFS(k+1, opt, p_sum, x);
    }
    

    正解部分
    按以上解法, 将 DFSDFS 换成 二进制枚举ACAC 了, 好奇怪.

    症结 ↑

    二进制枚举状态部分:

            for(reg int i = 1; i < 1<<cnt; i ++){
                    int p_sum = 1;
                    int p_cnt = 0;
                    for(reg int j = 1; j <= cnt; j ++)
                            if((1<<j-1) & i) p_cnt ++, p_sum = Lcm(p_sum, p[j]);
                    if(p_cnt & 1) Tmp_1 += x/p_sum;
                    else Tmp_1 -= x/p_sum;
            }
            return x-Tmp_1;
    
    

    实现部分
    没什么好说的.

    #include<cstdio>
    #include<cctype>
    #define reg register
    typedef long long ll;
    
    const int maxn = 105;
    
    int Test_Cnt;
    int N;
    int cnt;
    int p[maxn];
    ll Tmp_1;
    ll L;
    ll R;
    
    int Gcd(int a, int b){ return !b?a:Gcd(b, a%b); }
    int Lcm(int a, int b){ return a/Gcd(a, b)*b; }
    
    ll Calc(ll x){
            if(!x) return 0;
            Tmp_1 = 0;
            for(reg int i = 1; i < 1<<cnt; i ++){
                    int p_sum = 1;
                    int p_cnt = 0;
                    for(reg int j = 1; j <= cnt; j ++)
                            if((1<<j-1) & i) p_cnt ++, p_sum = Lcm(p_sum, p[j]);
                    if(p_cnt & 1) Tmp_1 += x/p_sum;
                    else Tmp_1 -= x/p_sum;
            }
            return x-Tmp_1;
    }
    
    void Work(){
            scanf("%lld%lld%d", &L, &R, &N);
            cnt = 0;
            for(reg int d = 2; d*d <= N; d ++)
                    if(N % d == 0){
                            p[++ cnt] = d;
                            while(N%d == 0) N /= d;
                    }
            if(N > 1) p[++ cnt] = N; //Attention
            printf("Case #%d: %lld
    ", ++ Test_Cnt, Calc(R) - Calc(L-1));
    }
    
    int main(){
            int T;
            scanf("%d", &T);
            while(T --) Work();
            return 0;
    }
    
    
  • 相关阅读:
    HDU2767 Proving Equivalences
    POJ2771 Guardian of Decency
    POJ1111 Image Perimeters
    简单就好
    工具乃思维的奴隶
    “年终奖”
    学点经济学知识(二)
    被忽略的技能
    猿类己见
    学点经济学知识(一)
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822570.html
Copyright © 2011-2022 走看看