题意:https://www.acwing.com/problem/content/1067/
Tyvj 两周年庆典要到了,Sam 想为 Tyvj 做一个大蛋糕。
蛋糕俯视图是一个 N×M 的矩形,它被划分成 N×M 个边长为 1×1×1 的小正方形区域(可以把蛋糕当成 N 行 M 列的矩阵)。
蛋糕很快做好了,但光秃秃的蛋糕肯定不好看!
所以,Sam 要在蛋糕的上表面涂抹果酱。
果酱有三种,分别是红果酱、绿果酱、蓝果酱,三种果酱的编号分别为 1,2,3。
为了保证蛋糕的视觉效果,Admin 下达了死命令:相邻的区域严禁使用同种果酱。
但 Sam 在接到这条命令之前,已经涂好了蛋糕第 K 行的果酱,且无法修改。
现在 Sam 想知道:能令 Admin 满意的涂果酱方案有多少种。请输出方案数 mod106。
若不存在满足条件的方案,请输出 0。
三进制状压,因为多了一种状态所以没办法用位运算简便的判断。
所以我们可以自己写函数。
#include <bits/stdc++.h> typedef long long ll; const int mod=1000000; using namespace std; int n,m,k,stat=1,cnt=1,ban;//stat是总的状态数,ban是第K行的状态 int sta[1009],dp[10009][1005]; bool check(int x){//检验是否有相邻的数 int temp=-1; for(int i=1;i<=m;i++){ if(temp==x%3) return false;//等于上一个数就不行 temp=x%3,x/=3; } return true; } bool judge(int l,int r){ for(int i=1;i<=m;i++){ if(l%3==r%3) return false; l/=3,r/=3; } return true; } int main() { cin>>n>>m>>k; stat=ll(pow(3,m)); for(int i=0;i<stat;i++) if(check(i)) sta[cnt++]=i; int z; for(int i=1;i<=m;i++)//读入第K行的状态 { cin>>z; ban=ban*3+z-1; } if(!check(ban)) {cout<<0;return 0;}//第K行连在了一起 int num;//记录第K行对应的下标 for(int i=1;i<cnt;i++) if(ban==sta[i]) num=i; for(int i=1;i<=n;i++) { if(i==k){ if(i==1) dp[1][num]=1; else{ for(int j=1;j<cnt;j++){ if(judge(sta[num],sta[j])) dp[i][num]=(dp[i][num]+dp[i-1][j])%mod; } } continue; } for(int j=1;j<cnt;j++)//枚举状态 { if(i==1) dp[i][j]=1; else{ for(int k=1;k<cnt;k++) { if(judge(sta[j],sta[k]))//两行的状态不冲突 dp[i][j]=(dp[i][j]+dp[i-1][k])%mod; } } } } ll ans=0; for(int i=1;i<cnt;i++) ans=(ans+dp[n][i])%mod; cout<<ans; }