zoukankan      html  css  js  c++  java
  • HDU 5768 Lucky7 (容斥原理 + 中国剩余定理 + 状态压缩 + 带膜乘法)

      题意:……应该不用我说了,看起来就很容斥原理,中国剩余定理……

      方法:因为题目中的n最大是15,使用状态压缩可以将所有的组合都举出来,然后再拆开成数组,进行中国剩余定理的运算,中国剩余定理能够求出同时满足余膜条件的最小整数x,x在(1,M)之间由唯一值,M是各个除数的乘积,所有符合条件的解为ans = x+k*M,可以知道在[1,R]这个区间内,有(M+R-x)/ M个k符合条件,然后在运算中为了防止溢出,所以使用了带膜乘法,就是将乘数转化为二进制,通过位移运算符,在中间过程中不断的取膜(看代码很容易明白)

      注意:为了简化运算,把(7,0)这一组加进去,带膜乘法中,需要使用同余膜定理把乘数转化为整数,因为欧几里德算法有可能返回负数,不转化会陷入死循环,我之前忘了,结果……题目给的样例都已经死在了里面……

      感悟:真不愧是多校训练赛,一个题目融合了这么多知识点。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define N 20
    #define LL long long
    int n,cnt;
    LL X,Y,p[N],a[N],Pt[N],At[N];
    int Get_Zuhe(int k){
        int ip;
        cnt = ip = 0;
        while(k){
            if(k&1){
                Pt[cnt] = p[ip];
                At[cnt] = a[ip];
                cnt++;
            }
            ip++;
            k >>= 1;
        }
        Pt[cnt] = 7;
        At[cnt] = 0;
        cnt++;
        return (cnt%2);
    }
    LL ex_gcd(LL a,LL b,LL &x,LL &y){
        if(b==0) {
            x=1; y=0;
            return a;
        }
        LL R = ex_gcd(b,a%b,y,x);
        y -= x*(a/b);
        return R;
    }
    LL Mul(LL x,LL y,LL M){
        LL ans = 0;
        while(y){
            //cout<<y<<endl;
            if(y&1) ans = (ans+x%M)%M;
            x = (x + x) % M;
            y >>= 1;
        }
        return ans;
    }
    LL China(){
        LL M = 1,m,ret = 0,x,y,L,R;
        for(int i = 0;i < cnt;i++) M *= Pt[i];
        for(int i = 0;i < cnt;i++){
            m = M/Pt[i];
            ex_gcd(m,Pt[i],x,y);
            x = (x+M)%M;///不要忘记转化为正数
            ret = (ret+Mul(Mul(m,x,M),At[i],M)%M) % M;
        }
        ret = (ret+M)%M;
       // printf("M = %I64d
    ",M);
      //  printf("ret = %I64d
    ",ret);
        R = (Y+M-ret)/M;
        L = (X-1+M-ret)/M;
        return R - L;
    }
    LL Solve(){
        int tmp = (1<<n),judge;
        LL all = Y/7 - (X-1)/7;
        LL sum = 0,ch;
        for(int i = 1;i < tmp;i++){
            judge = Get_Zuhe(i);
            ch = China();
         //   printf("china[%d] = %I64d
    ",i,ch);
            if(judge) sum -= ch;
            else sum += ch;
        }
        return (all - sum);
    }
    int main(){
       // freopen("A.in.cpp","r",stdin);
        int t,ca = 0;
        scanf("%d",&t);
        while(t--){
            scanf("%d %I64d %I64d",&n,&X,&Y);
            for(int i = 0;i < n;i++){
                scanf("%I64d %I64d",&p[i],&a[i]);
            }
            printf("Case #%d: %I64d
    ",++ca,Solve());
        }
        return 0;
    }
  • 相关阅读:
    洛谷 P1233 木棍加工
    洛谷 P3378 【模板】堆(小根堆)
    leetcode难度及面试频率
    设计模式大全
    多线程经典面试题
    查找子字符串----KMP算法深入剖析
    线程与进程的区别
    海量数据面试题----分而治之/hash映射 + hash统计 + 堆/快速/归并排序
    解析STL中典型的内存分配
    C++ 常量类型 const 详解
  • 原文地址:https://www.cnblogs.com/jifahu/p/5723321.html
Copyright © 2011-2022 走看看