刷水题找自信系列
【题目大意】
有一个$n*m$的矩阵,每个格子为一块土地,我们可以在土地上种草。每块土地有一个值,如果为$0$,则这块土地很贫瘠,不能种草;如果为$1$,则这块土地很肥沃,可以种草。现在要在这个矩阵上种草,要求不能有两个相邻的格子都种了草,求方案数。
【思路分析】
因为$n,mge12$,所以我们考虑状压。设$f[i][j]$表示第$i$行状态为$j$时的方案数,对于状态$j$要判断是否合法,即判断是否符合土地的贫瘠和肥沃的性质,以及同一行内是否有相邻的格子种了草。然后枚举上一行的状态$k$,如果没有上下两个相邻的格子种了草,则$f[i][j]+=f[i-1][k]$
初始值为$f[1][i]=1$,保证状态$i$合法。答案为$sum f[n][j]$,保证状态$j$合法。
【代码实现】
1 #include<bits/stdc++.h> 2 #define ri register int 3 #define ll long long 4 #define rl register ll 5 #define go(i,a,b) for(ri i=a;i<=b;i++) 6 #define back(i,a,b) for(ri i=a;i>=b;i--) 7 #define g() getchar() 8 #define il inline 9 #define pf printf 10 using namespace std; 11 il int fr(){ 12 ri w=0,q=1;char ch=g(); 13 while(ch<'0'||ch>'9'){if(ch=='-')q=-1;ch=g();} 14 while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=g(); 15 return w*q; 16 } 17 const int mod=1e9; 18 int n,m,f[15][1<<12],s[15],ans; 19 int main(){ 20 //freopen(".in","r",stdin); 21 //freopen(".out","w",stdout); 22 n=fr();m=fr(); 23 go(i,1,n)go(j,1,m){ 24 ri x=fr(); 25 if(x)s[i]|=1<<(m-j); 26 } 27 go(i,1,n)go(j,0,(1<<m)-1){ 28 if(((j<<1)&j)||((j>>1)&j))continue; 29 bool cnt=0; 30 go(k,0,m-1)if(((j>>k)&1)&&(!((s[i]>>k)&1))){cnt=1;break;} 31 if(cnt)continue; 32 if(i==1)f[i][j]=1; 33 else 34 go(k,0,(1<<m)-1){ 35 cnt=0; 36 go(t,0,m-1)if((j>>t)&(k>>t)){cnt=1;break;} 37 if(cnt)continue; 38 f[i][j]+=f[i-1][k];if(f[i][j]>=mod)f[i][j]-=mod; 39 } 40 if(i==n){ans+=f[i][j];if(ans>=mod)ans-=mod;} 41 } 42 pf("%d ",ans); 43 return 0; 44 }