bzoj 2669

来源:互联网 发布:卖软件代理 编辑:程序博客网 时间:2024/05/23 13:57

这种容斥套DP的题又好久没写了,我好菜啊

给我一周我也想不到这题的DP~~~

由于局部最小值只能有<=8个,

我们就从小到大枚举i,用f[i][j]表示当前枚举到i,局部最小值的状态为j的方案数

则:f[i][j]=f[i-1][j]*(可以放的位置+已经放的局部最小值-i+1)+{f[i-1][k^j]}(k是j的元素)

由于有点号的点被钦定不是局部最小值,就需要容斥一下

复杂度大概是能过的.

#include<cstdio>#include<cstring>#include<algorithm>#define mod 12345678using namespace std;char str[4][7],vis[4][7];int ans=0;int n,m,cnt[1<<9],f[30][1<<9],px[10],py[10];int dx[8]={1,-1,0,0,1,-1,1,-1},dy[8]={0,0,1,-1,1,1,-1,-1};bool inmap(int x,int y){return x>=0&&x<n&&y>=0&&y<m;}int calc(){//printf("---------------\n");//for(int i=0;i<n;++i)printf("%s\n",str[i]);int top=0;for(int i=0;i<n;++i)for(int j=0;j<m;++j)if(str[i][j]=='X')px[top]=i,py[top++]=j;memset(cnt,0,sizeof(cnt));for(int i=0;i<(1<<top);++i){memset(vis,0,sizeof(vis));for(int j=0;j<top;++j)if(~i&(1<<j)){for(int k=0;k<8;++k){int ni=px[j]+dx[k],nj=py[j]+dy[k];if(!inmap(ni,nj))continue;vis[ni][nj]=1;}vis[px[j]][py[j]]=1;}for(int j=0;j<n;++j)for(int k=0;k<m;++k)if(!vis[j][k])cnt[i]++;//printf("[%d:%d]",i,cnt[i]);}int p=n*m;memset(f,0,sizeof(f));f[0][0]=1;for(int i=1;i<=p;++i)for(int j=0;j<(1<<top);++j){for(int k=0;k<top;k++)if(j&(1<<k))(f[i][j]+=f[i-1][j^(1<<k)])%=mod;(f[i][j]+=1ll*f[i-1][j]*max(0,cnt[j]-i+1)%mod)%=mod;//printf("{%d}",f[i][j]);}//iprintf("[%d]",top);return f[p][(1<<top)-1];}void dfs(int x,int y,int f){if(y==m){ans=(ans+1ll*calc()*f%mod)%mod;return ;}else if(x==n){dfs(0,y+1,f);return;}else dfs(x+1,y,f);if(str[x][y]!='X'){for(int k=0;k<8;++k){int nx=x+dx[k],ny=dy[k]+y;if(inmap(nx,ny)&&str[nx][ny]=='X')goto end;}str[x][y]='X';dfs(x+1,y,-f);str[x][y]='.';end:;}}int main(){scanf("%d%d",&n,&m);for(int i=0;i<n;++i)scanf("%s",str[i]);dfs(0,0,1);printf("%d",(ans%mod+mod)%mod);}



0 0
原创粉丝点击