题解 AT2389 【[AGC016E] Poor Turkeys】

· · 题解

AT2389 [AGC016E] Poor Turkeys解题报告:

更好的阅读体验

题意

分析

神仙题。

我们设f_{i,j}=1i\ne j)表示:如果i要活着,那么以后j一定要为i“抵命”

可以用一个倒推的dp来O(n^2)求出f数组,具体地说:

S(i)为必须死去来抵i一命的集合。

然后,我们枚举点对(i,j)i<j),首先判断i,j是不是一定得死去,如果不是,那么很显然只有S(i)\cap S(j)=\varnothing才能让ij同时存活(一只火鸡不能同时给ij抵命)。

题解

#include<stdio.h>
#include<bitset>
using namespace std;
const int maxn=405,maxm=100005;
int n,m,ans;
int a[maxm],b[maxm],no[maxn];
bitset<maxn>keep[maxn];
int main(){
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&a[i],&b[i]);
    for(int i=1;i<=n;i++){
        keep[i][i]=1;
        for(int j=m;j>=1;j--){
            if(keep[i][a[j]]&&keep[i][b[j]]){
                no[i]=1;
                break;
            }
            if(keep[i][a[j]])
                keep[i][b[j]]=1;
            else if(keep[i][b[j]])
                keep[i][a[j]]=1;
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            if(no[i]==0&&no[j]==0&&(keep[i]&keep[j]).count()==0)
                ans++;
    printf("%d\n",ans);
    return 0;
}