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