0219考试总结

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







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值