HDU - 5768 Lucky7 (中国剩余定理+容斥)

题意:统计区间[L,R]中满足模7余0,且对所有N个数对(mi,ri)使得  x != ri (mod mi) 的x的数量。

分析:x == ri (mod mi)可以转化为模线性方程。枚举满足k(1<=k<=n)个线性方程构成方程组的解在区间[L,R]中的个数。需要减去这些数目,所以根据容斥原理,奇减偶加。

题目保证每个mi都是素数,所以用互素与不互素的两种中国剩余定理模板都可以求解。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
LL Exgcd(LL a,LL b,LL &x,LL &y ) {
    if ( b == 0 ) {
        x = 1;
        y = 0;
        return a;
    }
    LL d =  Exgcd(b, a%b, x, y), temp = x;
    x = y;
    y = temp-a/b*y;
    return d;
}
int n;
LL Li,Ri;
LL M[20],R[20];

inline LL count(LL k, LL m, LL x)
{ 
    return (m - k + x) / m;
}

LL CRT(int s)              
{
    LL a1,r1,a2,r2;
    LL a,b,c,x,y,d;
    a1 = M[n],r1 =R[n];
    for(int i=0;i<n;i++){
        if(s&(1<<i)){
            a2 = M[i], r2 = R[i];
            a=a1,b=a2,c=r2-r1;
            d = Exgcd(a,b,x,y);
            if(c%d!=0) return 0;
            LL t=b/d;
            x=(x*(c/d)%t+t)%t;
            r1=a1*x+r1;
            a1=a1*(a2/d);
        }
    }
    r1 = (r1%a1+a1)%a1;
    return count(r1,a1,Ri) - count(r1,a1,Li-1);
}

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int T,cas=1; scanf("%d",&T);
    while(T--){
        scanf("%d %lld %lld ",&n, &Li, &Ri);
        for(int i=0;i<n;++i){
            scanf("%lld %lld ",&M[i],&R[i]);
        }
        M[n] = 7,R[n] = 0;                      //多加一个模7余0的方程

        LL ans=Ri/7-Li/7;;
        if(Li%7==0) ans++;
        
        int up = 1<<n;
        for(int i=1;i<up;++i){
            int cnt = __builtin_popcount(i);
            if(cnt&1) ans -=CRT(i);           //反过来算,奇减偶加
            else ans += CRT(i);
        }
        printf("Case #%d: %lld\n",cas++,ans);
    }
    return 0;
}

 

posted @ 2018-08-22 11:46  xiuwenL  阅读(130)  评论(0编辑  收藏  举报