hdu 5768 容斥+模线性方程组

http://acm.hdu.edu.cn/showproblem.php?pid=5768

 

题意:给你一个范围,让你找到满足条件的数有多少个。。条件:是7的倍数,%Xi=ai。。

 

思路:这个问题明显是个并集这样的问题。。纸上大概写一写就能发现是个容斥的问题。。所以我们先预处理出来每种情况模线性方程的解。。。之后用dfs+状压进行容斥原理(就是把表达式展开+-+-。。。)。。到这里这个题就做完了。。

 

代码:

 

#include <bits/stdc++.h>
using namespace std;

int n;
int vis[1<<16];
long long dp[1<<16][2];
long long M[16],A[16];
long long extend_gcd(long long a,long long b,long long &x,long long  &y){
    if(a == 0 && b == 0)return -1;
    if(b ==0 ){
        x = 1;
        y = 0;
        return a;
    }
    long long d = extend_gcd(b,a%b,y,x);
    y -= a/b*x;
    return d;
}
long long m[16],a[16];//模数为m,余数为a, X % m = a
bool solve(long long &m0,long long &a0,long long m,long long a){
    long long y,x;        /*  * 无解返回false,有解返回true;  * 解的形式最后为 a0 + m0 * t  (0<=a0<m0)  */
    long long g = extend_gcd(m0,m,x,y);
    if( abs(a - a0)%g )return false;
    x *= (a - a0)/g;
    x %= m/g;
    a0 = (x*m0 + a0);
    m0 *= m/g;
    a0 %= m0;
    if( a0 < 0 )a0 += m0;
    return true;
}
bool MLES(long long &m0 ,long long &a0,int n)//解为  X = a0 + m0 * k
{
    bool flag = true;
    m0 = 1;
    a0 = 0;
    for(int i = 0; i < n; i++)
        if( !solve(m0,a0,m[i],a[i]) ){
            flag = false;
            break;
        }
    return flag;
}

void init(int bts){
    int cnt=0;
    for(int i=0;i<n;i++){
        if(bts&(1<<i)){
            m[cnt]=M[i];
            a[cnt++]=A[i];
        }
    }
    m[cnt]=7;
    a[cnt++]=0;
    MLES(dp[bts][0],dp[bts][1],cnt);
}

long long sl(int bts,long long T){
    long long ret=0;
    ret+=T/dp[bts][0];
    if(dp[bts][1]<=T%dp[bts][0]) ret++;
    return ret;
}
long long TM;
void dfs(int bts,long long T,int c){
    long long ret=0;
    vis[bts]=1;
    if(bts!=0) ret=sl(bts,T);
    if(c) TM+=ret;
    else{
       TM-=ret;
     //  cout<<ret<<"我是会减少的!!!\n";
    }
    for(int i=0;i<n;i++){
        int nxt=bts|(1<<i);
        if(!vis[nxt]){
            dfs(nxt,T,c^1);
        }
    }
}

int main(){
    int t,cas=1;
    scanf("%d",&t);
    while(t--){
        long long x,y;
        scanf("%d%lld%lld",&n,&x,&y);
        x--;
        for(int i=0;i<n;i++) scanf("%lld%lld",&M[i],&A[i]);
        for(int i=1;i<(1<<n);i++) init(i);
       // cout<<"FFFF\n";
        memset(vis,0,sizeof(vis));
        TM=0;
        dfs(0,x,0);
        long long X=x/7-TM;
        memset(vis,0,sizeof(vis));
        TM=0;
        dfs(0,y,0);
        long long Y=y/7-TM;
        printf("Case #%d: ",cas++);
        cout<<Y-X<<endl;
    }
}



posted @ 2016-07-30 15:41  zhangxianlong  阅读(93)  评论(0编辑  收藏  举报