洛谷 P1896 [SCOI2005]互不侵犯King(bzoj P1087 [SCOI2005]互不侵犯King)

xiaoxiao2021-02-28  82

传送门

虽然水题一道但是还是调了很长时间,最近做题状态很差啊,很迷。。

状压dp,比较简单没什么优化,把每一行作状态记录,所以跑了32ms(orz 0ms大神),设f[i][j][k]表示第i行状态为j用了k个皇的方案数,然后有一个很弱智的优化,把可行的状态处理出来,这里的可行是指上下行不斥每一行中的方格彼此不斥的状态。然后就有f[i][j][k]=f[i-1][l][k-cnt[j]](cnt[i]表示状态i的国王个数)。

注意:long long

代码:

#include<iostream> #include<stdio.h> #include<math.h> #define ll long long using namespace std; const int Maxn=600; int p[Maxn],m[Maxn][Maxn],cnt[Maxn]; ll f[20][Maxn][Maxn]; int main() { int n,k,tmp=0,x; ll ans=0; scanf("%d%d",&n,&k); x=pow(2,n)-1; for(int i=0;i<=x;i++) if((i&(i<<1))==0) { int s=0; for(int j=i;j;j>>=1) s+=(j&1); if(s<=k) { p[++tmp]=i; cnt[tmp]=s; } } for(int i=1;i<=tmp;i++) for(int j=1;j<=tmp;j++) m[i][j]=m[j][i]=((p[i]>>1)&p[j])||(p[i]&p[j])||((p[j]>>1)&p[i])?0:1; for(int i=1;i<=tmp;i++) f[1][i][cnt[i]]=1; for(int i=2;i<=n;i++) for(int j=1;j<=tmp;j++) for(int s=1;s<=tmp;s++) if(m[j][s]==1) for(int l=cnt[s];l<=k;l++) f[i][s][l]+=f[i-1][j][l-cnt[s]]; for(int i=1;i<=tmp;i++) ans+=f[n][i][k]; printf("%lld",ans); return 0; }

转载请注明原文地址: https://www.6miu.com/read-46922.html

最新回复(0)