hdu 5768 容斥+模线性方程组

本文详细解析了HDU 5768题目,通过使用容斥原理解决模线性方程组问题。文章分享了一种预处理模线性方程解的方法,并采用DFS+状态压缩实现容斥原理求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值