JZOJ.5230【NOIP2017模拟8.5】队伍统计
n<=20,显然要状压DP,将排队的状态压成一个数来表示
对于一个队伍状态S,令F[S][k]表示S状态违反了k条矛盾的合法方案数,则有
F[S|2i-1][k+num(S&power[i])]=F[S|2i-1][k+num(S&power[i])]+F[S][k]
其中i表示某个不在队伍的人,num(i)表示i在二进制下1的个数,power[i]表示必须排在i后面的人的情况。
(实际操作中发现power[i]储存排在i后面的人的情况的时候运行速度远不及power[i]储存排在i前面的情况)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 using namespace std; 3 const int qaq=1000000007; 4 int f[1<<20][21],power[21],n,m,t; 5 int main(){ 6 freopen("count.in","r",stdin); 7 freopen("count.out","w",stdout); 8 scanf("%d%d%d",&n,&m,&t); 9 int u,v; 10 for (int i=1;i<=m;i++){ 11 scanf("%d%d",&u,&v); 12 power[u]|=1<<(v-1); //power[v]|=1<<(u-1); 13 } 14 f[0][0]=1; 15 for (int i=0;i<(1<<n);i++) 16 for (int j=0;j<=t;j++) 17 if (f[i][j]) 18 for (int k=1;k<=n;k++) 19 if ((i&(1<<(k-1)))==0){ 20 int qwq=power[k]&i; //int qwq=power[k]^(power[k]&i); 21 int sum=0; 22 while (qwq){ 23 sum++; 24 qwq&=(qwq-1); 25 } 26 if (j+sum<=t){ 27 f[i|(1<<(k-1))][j+sum]+=f[i][j]; 28 if (f[i|(1<<(k-1))][j+sum]>=qaq) 29 f[i|(1<<(k-1))][j+sum]%=qaq; 30 } 31 } 32 int ans=0; 33 for (int i=0;i<=t;i++) 34 ans=(ans+f[(1<<n)-1][i])%qaq; 35 printf("%d\n",ans); 36 return 0; 37 }
注意运算优先级,注意运算优先级,注意运算优先级!!!