nssl 1478.题

D e s c r i p t i o n Description Description

n n n个苹果, m m m个人依次来吃苹果,第 i i i个人会选择两个苹果 u i , p i u_i,p_i ui,pi

对于这两个苹果的状态:

  1. 如果两个都没被吃,那么它会选择吃掉其中一个
  2. 如果有一个没被吃,会吃掉那个
  3. 如果都被吃了,那就吃个寂寞

求所有满足两个苹果都没被吃的点对

数据范围: n ≤ 400 , m ≤ 5 × 1 0 4 n\leq 400,m\leq 5\times 10^4 n400,m5×104


S o l u t i o n Solution Solution

g [ i ] [ j ] g[i][j] g[i][j]表示如果 i i i活着, j j j是否必死
f [ i ] f[i] f[i]表示 i i i是否能存活

初态 g [ i ] [ i ] = 1 g[i][i]=1 g[i][i]=1(表示自环)

如果对于一个人的要求 j j j
如果 g [ i ] [ u [ j ] ] = 1 g[i][u[j]]=1 g[i][u[j]]=1 g [ i ] [ v [ j ] ] = 0 g[i][v[j]]=0 g[i][v[j]]=0,说明 u [ j ] u[j] u[j]必死,则 v [ j ] v[j] v[j]也必死,所以 g [ i ] [ v [ j ] ] = 1 g[i][v[j]]=1 g[i][v[j]]=1
反过来同理
但如果两个同时为1,说明 i i i必死,则 f [ i ] = 0 f[i]=0 f[i]=0

统计答案的时候只需要枚举中转点判断 i , j i,j i,j是否合法即可

时间复杂度: O ( n m + n 3 ) O(nm+n^3) O(nm+n3)


C o d e Code Code

#include
#include
#include
#define LL long long
using namespace std;int n,m,u[50010],v[50010],ans;
bool g[401][401],f[401],flag;
inline LL read()
{
	char c;LL d=1,f=0;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
signed main()
{
	n=read();m=read();
	for(register int i=1;i<=m;i++) u[i]=read(),v[i]=read();
	for(register int i=1;i<=n;i++)
	{
		g[i][i]=true;
		for(register int j=m;j>0;j--)
		{
			if(g[i][u[j]]&&g[i][v[j]]) {f[i]=true;break;}
			g[i][u[j]]=g[i][v[j]]=g[i][u[j]]|g[i][v[j]];
		}
	}
	for(register int i=1;i<=n;i++)
	{
		for(register int j=1;j<=n;j++)
		{
			if(i==j) continue;
			if(f[i]||f[j]) continue;
			flag=true;
			for(register int k=1;k<=n;k++) if(g[i][k]&&g[j][k]) {flag=false;break;}
			ans+=flag;
		}
	}
	printf("%d\n",ans/2);
}

你可能感兴趣的:(dp)