BZOJ3444: 最後的晚餐


【問題背景】
高三的學長們就要離開學校,各奔東西了。某班n人在舉行最後的離別晚餐時,飯店老闆覺得十分糾結。因爲有m名學生偷偷找他,要求和自己暗戀的同學坐在一起。
【問題描述】
飯店給這些同學提供了一個很長的桌子,除了兩頭的同學,每一個同學都與兩個同學相鄰(即坐成一排)。給出所有信息,滿足所有人的要求,求安排的方案總數(這個數字可能很大,請輸出方案總數取餘989381的值,也可能爲0)。

這問題背景真真真不煽情啊。咳咳,走遠了。


其實坐不坐在一起是無向的,我挨着你坐,那你肯定也挨着我坐。所以建一個無向森林,把所有要捱到一起的東西連上,然後發現這個森林裏面的每一個聯通塊其實都應該是一條鏈。否則肯定無解。把所有鏈找出來之後打包,每一條鏈是有兩種方法的順這和倒着,若有a個人沒有要求,一共有b條鏈那答案就是
那現在就來考慮怎麼找鏈,好像可以直接用並查集維護。我比較沙茶,寫的拓撲(雖然是無向圖,但我建立的是雙向有向邊,拓撲每次考慮入度≤1的去搞)。
先考慮有兩種情況是無解的,第一種就是鏈分叉了,第二種就是成環了。
第一種直接看如果連了A,B一條新邊,看A,B的入度若≥3,那肯定就分叉了。直接0.
第二種就在拓撲中記錄已經訪問了多少點,若和有要求的人數不同,那麼肯定就有環了。
然後這個水題就完了。
這種寫法有個trick,就是如果A暗戀B,B暗戀A,這相當於有重邊了,我每次都建立兩個單向邊,這下就建立了4個單向邊,就搞成環了。
哎這麼美妙的事情,爲什麼在程序中是個TRICK!哎,不是每件好事的發生對於人類的進展都是有益的。唉唉唉。。爲什麼我非要破壞了這美好一刻。
說點題外話:每個人都只會暗戀一個,所以只用開一個數組記一下,雖然我暴力map純二啊!(這爲什麼是題外話。。)
最後:希望大家都有一個雙向邊,但一定不要出現多叉。

#include <cstdio>
#include <algorithm>
#include <map>
#define rep(i,l,r) for (int i=l;i<=r;++i)
typedef long long LL;
int getx(){
	char c;int x;
	for (c=getchar();c<'0'||c>'9';c=getchar());
	for (x=0;c>='0'&&c<='9';c=getchar())
		x=(x<<3)+(x<<1)+c-'0';
	return x;
}
const LL MOD=989381;
const int MAX_N=500005;
int first[MAX_N],next[MAX_N<<1],to[MAX_N<<1];
int rd[MAX_N];
int tal=0;
void tjb(int x,int y){
	next[++tal]=first[x];
	first[x]=tal;
	to[tal]=y;
	rd[y]++;
}
int tot=0;
bool vis[MAX_N];
void topo(int v,int fa){
	vis[v]=true;tot--;
	for (int k=first[v];k;k=next[k]){
		int u=to[k];
		if (u==fa) continue;
		if (--rd[u]<=1) topo(u,v);
		}
}
LL power(LL a,LL b){
	LL res=1;
	for (;b;a=((LL)a*a)%MOD,b>>=1)
		if (b&1) res=((LL)res*a)%MOD;
	return res;
}
int n,m;
std::map<int,bool> edge[MAX_N];
bool choose[MAX_N];
int main(){
	n=getx(),m=getx();
	rep(i,1,m){
		int x=getx(),y=getx();
		if (x>y) x^=y,y^=x,x^=y;
		if (!choose[x]){choose[x]=true;tot++;}
		if (!choose[y]){choose[y]=true;tot++;}
		if (!edge[x][y]){
			tjb(x,y),tjb(y,x);
			if (rd[x]>2||rd[y]>2) {printf("0");exit(0);}
			edge[x][y]=true;
			}
		}
	int s=n-tot;
	int k=0;
	rep(i,1,n)
		if (!vis[i]&&rd[i]==1){k++;topo(i,0);}
	if (tot>0){printf("0");exit(0);}
	LL ans=1;
	rep(i,1,s+k) ans=ans*i%MOD;
	printf("%d\n",ans*power(2,k)%MOD);
}



發佈了41 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章