T1
【题目大意】
n个人,每个人都有一枚邮票和一些喜欢的邮票。每次可以把任意个人的邮票进行一次轮换,并且轮换后每个人必须拿着一枚喜欢的邮票,求最终能否让每个人都拿到一枚喜欢的邮票。
【吐槽】
这题出得神坑,直把人往tarjan上带。
正解如下:
其实那个交换方式只是吓唬人的。
对于每一种分配方案,我们都可以构造出一种交换方案达到这样的效果。
所以就是判断能不能给每个人分配一枚他喜欢的邮票。
二分图匹配,左边是人右边是邮票,每个人向喜欢的邮票连边,求是否存在完备匹配。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
#define FILE "Book"
#define MAXN 20010
#define INF 1000000000
#define up(i,j,n) for(int i=j;i<=n;++i)
#define dn(i,j,n) for(int i=j;i>=n;--i)
struct node{int y,next,v,rel;}e[MAXN*4];
int n,m,S,T,len,Link[MAXN],q[MAXN],level[MAXN];
void insert(int x,int y,int v){
e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;e[len].rel=len+1;
e[++len].next=Link[y];Link[y]=len;e[len].y=x;e[len].v=0;e[len].rel=len-1;
}
bool bfs(){
memset(level,-1,sizeof(level));
int head=0,tail=1; level[S]=0; q[1]=S;
while(++head<=tail){
for(int i=Link[q[head]];i;i=e[i].next){
if(e[i].v&&level[e[i].y]<0){
q[++tail]=e[i].y;
level[q[tail]]=level[q[head]]+1;
}
}
}
return level[T]>=0;
}
int MAXFLOW(int x,int flow){
if(x==T) return flow;
int d=0,maxflow=0;
for(int i=Link[x];i&&maxflow<flow;i=e[i].next){
if(level[x]+1==level[e[i].y]&&e[i].v){
if(d=MAXFLOW(e[i].y,min(e[i].v,flow-maxflow))){
e[i].v-=d; e[e[i].rel].v+=d; maxflow+=d;
}
}
}
if(!maxflow) level[x]=-1;
return maxflow;
}
void solve(){
int d(0),ans(0);
while(bfs()) while(d=MAXFLOW(S,INF)) ans+=d;
puts(ans==n?"YES":"NO");
}
void pre(){len=0;memset(Link,0,sizeof(Link));}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
while(~scanf("%d%d",&n,&m)){
pre();
up(i,1,m) {int x,y;scanf("%d%d",&x,&y);insert(x,y+n,1);}
S=0;T=n*2+1;
up(i,1,n) insert(S,i,1),insert(i+n,T,1);
solve();
}
return 0;
}
T2
蒟蒻并不会写,留个坑。。。
T3
【题目大意】
给出n个变量,m个方程,以及t个限制。
方程是一些变量的和等于一个数,限制是某个变量不超过多少。
变量只能是非负整数,求解的个数。
【题解】
组合数学+容斥原理
首先如果这题没有t的限制,那么就是JZYZOI1890的原题了。
用挡板法可知方程解的个数为c[k+n-1][k-1]
如果有限制的话,我们用容斥原理进行计算即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
#define FILE "Equation"
#define MAXN 1000100
#define up(i,j,n) for(ll i=j;i<=n;++i)
#define dn(i,j,n) for(ll i=j;i>=n;--i)
namespace INIT{
char buf[1<<15],*fs,*ft;
inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline ll read(){
ll x=0,f=1; char ch=getc();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getc();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getc();}
return x*f;
}
}using namespace INIT;
ll n,m,t,sum[MAXN],id[MAXN],c[MAXN],d[MAXN],iv[MAXN],inv[MAXN],vis[MAXN],use[MAXN],delt[MAXN],frac[MAXN],UP[MAXN];
ll get(ll a,ll b){return frac[a]*iv[b]%mod*iv[a-b]%mod;}
ll fast(ll a,ll b){ll ans(1);for(;b;b>>=1,a=a*a%mod)if(b&1)ans=ans*a%mod;return ans;}
void pre(){
frac[0]=frac[1]=iv[0]=iv[1]=1;
up(i,2,2000000) frac[i]=frac[i-1]*i%mod,iv[i]=(iv[mod%i]*(-mod/i)%mod+mod)%mod;
up(i,2,2000000) iv[i]=iv[i]*iv[i-1]%mod;
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read(); m=read(); pre();
up(i,1,m){
sum[i]=read();
up(j,1,sum[i]) id[read()]=i;
c[i]=read();
}
t=read(); ll lim=1<<t,pr=1;
up(i,1,t) d[i]=read(),UP[i]=read();
up(i,1,m){
ll temp=get(c[i]+sum[i]-1,sum[i]-1);
pr=pr*temp%mod;
inv[i]=fast(temp,mod-2);
}
ll ans=pr;
up(i,1,lim-1){
ll flag=1,top=0;
up(j,1,t)if(i&(1<<(j-1))){
flag=-flag;
if(vis[id[d[j]]]!=i){
vis[id[d[j]]]=i;
delt[id[d[j]]]=0;
use[++top]=id[d[j]];
}
delt[id[d[j]]]+=UP[j]+1;
}
ll temp(pr);
up(j,1,top){
temp=temp*inv[use[j]]%mod;
temp=temp*get(c[use[j]]-delt[use[j]]+sum[use[j]]-1,sum[use[j]]-1)%mod;
}
ans+=temp*flag; ans=(ans%mod+mod)%mod;
}
printf("%lld\n",ans);
return 0;
}