ACM/ICPC 之 中国剩余定理+容斥原理(HDU5768)

  二进制枚举+容斥原理+中国剩余定理

 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;

#define MAXN 20
typedef long long LL;

int n;
int s[MAXN];
LL a[MAXN], m[MAXN];    //a是余数,m是除数

LL extented_gcd(LL a,LL b, LL &x, LL &y)   //扩展欧几里得
{
    if(a == 0 && b == 0) return -1;
    if(b == 0){
        x = 1; y = 0; return a;
    }
    LL d = extented_gcd(b, a%b, y, x);
    y -= a/b*x;
    return d;
}

LL mult(LL a, LL k, LL m){  //快速乘法
    LL res = 0;
    while(k){
        if(k & 1LL) res = (res + a) % m;
        k >>= 1;
        a = (a << 1) % m;
    }
    return res;
}

//x = ai(mod mi)  mi之间互素
//M = m1 * m2 * ... * mi
//Mi'*Mi = 1 (mod mi)   Mi = M/mi
//x = sigma(ai * Mi * M') % M
LL CRT(LL l, LL r)  //中国剩余定理
{
    LL M = 1, ans = 0;
    for (int i = 0; i <= n; ++i)
        if(s[i]) M *= m[i];
    for(int i = 0;i <= n;i++)
    {
        if(s[i]){
            LL Mi = M/m[i];
            LL x,y;
            extented_gcd(Mi, m[i], x,y);    //求Mi*x=1(mod m[i])
            x = (x%m[i] + m[i]) % m[i];
            ans = (ans+mult(a[i]*Mi % M, x, M)) % M;    //计算最小解
        }
    }
    return (r+M-ans)/M - (l-1+M-ans)/M; //计算[l,r]间解的个数
}

int main()
{
    //freopen("in", "r", stdin);
    int T, cas = 0;
    scanf("%d", &T);
    while(T--){
        LL l, r;
        scanf("%d%lld%lld", &n, &l, &r);
        memset(s, 0, sizeof(s));
        m[n] = 7; a[n] = 0; s[n] = 1;
        for(int i = 0;i < n;i++)
            scanf("%lld%lld", &m[i], &a[i]);
        LL ans = 0;
        int all = 1 << n;
        for(int i = 0;i < all;i++){ //二进制枚举同余方程
            int t = i, k = 0;
            for(int j = 0;j < n;j++){
                s[j] = t & 1;
                t >>= 1;
                k += s[j];  //计算同余方程个数
            }
            k = k & 1 ? -1 : 1;//容斥定理-奇减偶加
            ans += 1LL * k * CRT(l, r);
        }
        printf("Case #%d: %lld\n", ++cas, ans);
    }
    return 0;
}

 

posted @ 2016-08-16 11:15  文字失效  阅读(512)  评论(0编辑  收藏  举报