NC20485. [ZJOI2009]多米诺骨牌
描述
输入描述
第一行两个整数n,m。
接下来n 行,每行m个字符,表示这个矩形表格。 其中字符“x” 表示这个位置有障碍,字符“.” 表示没有障碍。
输出描述
一行一个整数,表示不同的放置方法数mod 19901013 的值。
示例1
输入:
3 3 ... ... ...
输出:
2
C++11(clang++ 3.9) 解法, 执行用时: 599ms, 内存消耗: 1656K, 提交时间: 2019-03-09 13:48:41
#include<iostream> #include<cstdio> #define ll long long #define N 20 #define MN 40000 #define M 19901013 using namespace std; ll m,n,dp[N][N][N][N],tmp[2][MN],f[N],num[N],top,ans; char str[N]; bool mm[N][N]; inline ll ask(ll u,ll v) { return (u>>v)&1; } inline void work(ll w,ll u,ll v) { ll i,j,k,l,t,t2,zt,tot=(1 << (v-u+1))-1; bool now=0,nxt; for(i=0; i<=tot; i++) tmp[0][i]=0; t2=0;for(i=u;i<=v;i++) if(mm[w][i]) t2|=(1 << (i-u)); tmp[0][t2]=1; for(i=w+1; i<=m+1; i++) { zt=0; for(j=u,t=0; j<=v; j++,t++) { zt|=(mm[i][j] << t); nxt=now^1; for(k=0; k<=tot; k++) tmp[nxt][k]=0; for(k=0; k<=tot; k++) { if(!tmp[now][k]) continue; t2=k; if(ask(t2,t)!=mm[i][j]) t2^=(1 << t); tmp[nxt][t2]=(tmp[nxt][t2]+tmp[now][k])%M; if(ask(k,t)) continue; if(j!=v&&!ask(k,t+1)) { t2=k|(1 << (t+1)); if(ask(t2,t)!=mm[i][j]) t2^=(1 << t); tmp[nxt][t2]=(tmp[nxt][t2]+tmp[now][k])%M; } if(!mm[i][j]) { t2=k|(1 << t); tmp[nxt][t2]=(tmp[nxt][t2]+tmp[now][k])%M; } } now=nxt; } dp[w][u][i-1][v]=tmp[now][zt]; } } int main() { ll i,j,k,tot,p,q,t,u,d; cin>>m>>n; for(i=1; i<=m; i++) { scanf("%s",str+1); for(j=1; j<=n; j++) { mm[i][j]=(str[j]!='.'); } } for(i=1; i<=n; i++) { for(j=i; j<=n; j++) { for(k=1; k<=m; k++) { work(k,i,j); } } } tot=(1 << (n-1))-1; for(i=0; i<=tot; i++) { top=0; num[++top]=0; for(j=0; j<n-1; j++) { if(ask(i,j)) num[++top]=j+1; } num[++top]=n; for(d=1; d<=m; d++) { for(u=1; u<=d; u++) { t=1; for(j=2; j<=top; j++) { p=num[j-1]+1,q=num[j]; t=t*dp[u][p][d][q]%M; } if(u==1) f[d]=t; else f[d]-=t*f[u-1]%M,f[d]%=M; } } f[m]=(f[m]+M)%M; if(top&1) ans-=f[m]; else ans+=f[m]; ans%=M; } cout<<(ans+M)%M; }