NKOJ 5140 大吉大利 晚上喫雞

問題描述

何老闆養了n只雞(編號1到n)。何老闆打算從今天開始,連續m晚都喫雞。
每晚,何老闆會選一對指定編號的雞出來。若兩隻雞都活着,那麼他會隨便喫掉其中一隻;若只有一隻活着,另一隻之前已經被吃了,就喫還活着那隻;若兩隻雞都已被喫掉了,當晚就不喫雞。
何老闆想知道,m天后,可能有多少對雞同時活着?請你幫他算一算。(如果一對雞存活的概率>0,我們認爲他們可能活着)

輸入格式

第一行,兩個整數n和m
接下來m行,每行兩個整數x和y,第i行表示第i天選出的兩隻雞的編號。

輸出格式

一行,一個整數,表示最後還存活的雞的對數。

我們來分析一下第xx雞能夠存活下來的條件。

假設與第xx雞配對的雞按照順序分別爲y1,y2,...,yky_1,y_2,...,y_k

xxyky_k中,xx要存活,那麼yky_k就要被喫

xxyk1y_{k-1}中,xx要存活,那麼yk1y_{k-1}就要被喫

xxy1y_1中,xx要存活,那麼y1y_1就要被喫。

也就是說,如果某隻雞要存活下來,那麼與它配對的所有其他雞都要被喫。

所以我們設立一個狀態liv[x][y]=1liv[x][y]=1,表示第xx只要存活下來,第yy只雞必須活着等着爲xx犧牲被喫。

那麼第xx只雞不能存活的條件呢?

假設第aa只雞與第bb只雞配對了,並且liv[x][a]==liv[x][b]==1liv[x][a]==liv[x][b]==1

也就是說xx要存貨下來,那麼aabb都要存活下來,但是a,ba,b只能存活下來一個,於是在這種情況下第xx只雞必死。

接下來討論求解,也就是哪些對雞可以存活。

我們假設這對雞爲x,yx,y

那麼這對雞的存活條件爲如果存在liv[x][z]=1liv[x][z]=1,那麼liv[y][z]!=1liv[y][z]!=1

時間複雜度:O(n3+nm)O(n^3+nm)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define db double
#define sg string
#define ll long long
#define rel(i,x,y) for(ll i=(x);i<(y);i++)
#define rep(i,x,y) for(ll i=(x);i<=(y);i++)
#define red(i,x,y) for(ll i=(x);i>=(y);i--)
#define res(i,x) for(ll i=head[x];i;i=nxt[i])
using namespace std;

const ll N=405;
const ll M=1e5+5;
const ll Inf=1e18;
const ll Mod=1e9+7;
const db Eps=1e-10;

ll n,m,ans,a[M],b[M],flg[N],liv[N][N];

inline ll read() {
	ll x=0;char ch=getchar();bool f=0;
	while(ch>'9'||ch<'0'){if(ch=='-')f=1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return f?-x:x;
}

int main() {
	n=read(),m=read();
	
	rep(i,1,m) a[i]=read(),b[i]=read();
	
	rep(i,1,n) {
		liv[i][i]=1;
		
		red(j,m,1) {
			ll fa=liv[i][a[j]],fb=liv[i][b[j]];
			
			if(fa&&fb) {
				flg[i]=1;break;
			} else {
				if(fa) liv[i][b[j]]=1;
				if(fb) liv[i][a[j]]=1;
			}
		}
	}
	
	rep(i,1,n) if(!flg[i]) rep(j,i+1,n) if(!flg[j]) {
		ll flag=1;
		
		rep(k,1,n) if(liv[i][k]&&liv[j][k]) {
			flag=0;break ;
		}
		
		if(flag) ans++;
	}
	
	printf("%lld\n",ans);

	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章