正题
题目大意
nnn个人排队,mmm个条件(u,v)(u,v)(u,v)表示uuu要排在vvv前,可以去掉kkk个,求方案总数
解题思路
考虑依次插入人在队头
对于状态1表示已经在队列里,0表示不在
fi,jf_{i,j}fi,j表示iii表示状态,jjj表示违背了的条件个数。
然后枚举队头的是哪个人,计算出插入他前的状态lastlastlast和将他插入队头会违背的条件个数noknoknok。
动态转移fi,j+=flast,j−nokf_{i,j}+=f_{last,j-nok}fi,j+=flast,j−nok
codecodecode
#include<cstdio>
#define N 21
using namespace std;
const int XJQ=1e9+7;
int n,m,k,atk[N],f[1<<N][N],ans,MS;
int count_one(int x){int ans=0;while(x){x-=(x&-x);ans++;}return ans;
}
int main()
{freopen("count.in","r",stdin);freopen("count.out","w",stdout);scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);atk[y-1]|=(1<<(x-1));}MS=1<<n;f[0][0]=1;for(int i=0;i<MS;i++)for(int j=0;j<n;j++)if((i>>j)&1){int last=i^(1<<j);int nok=count_one(atk[j]&last);for(int q=nok;q<=k;q++)(f[i][q]+=f[last][q-nok])%=XJQ;}for(int i=0;i<=k;i++)ans=(ans+f[MS-1][i])%XJQ;printf("%d",ans);
}