涂抹果酱

题面

Tyvj 两周年庆典要到了,Sam 想为 Tyvj 做一个大蛋糕。蛋糕俯视图是一个 $N×M$ 的矩形,它被划分成 $N×M$ 个边长为 $1×1$ 的小正方形区域(可以把蛋糕当成 $N$ 行 $M$ 列的矩阵)。蛋糕很快做好了,但光秃秃的蛋糕肯定不好看!所以,Sam 要在蛋糕的上表面涂抹果酱。果酱有三种,分别是红果酱、绿果酱、蓝果酱,三种果酱的编号分别为 $1,2,3$。为了保证蛋糕的视觉效果,Admin 下达了死命令:相邻的区域严禁使用同种果酱。但 Sam 在接到这条命令之前,已经涂好了蛋糕第 $K$ 行的果酱,且无法修改。 现在 Sam 想知道:能令 Admin 满意的涂果酱方案有多少种。请输出方案数 $\mod 10^6$。若不存在满足条件的方案,请输出 $0$。

思路

我们设$f[i][j]$表示第$i$行状态为$j$时的方案数。

预处理

先读入数据,在读入过程中将$3^1$~$3^m$算出,用$lg[i]$表示$3^i$。

然后压缩指定行$k$的状态$s$,初始$s=0$,$now$为当前位置上的数,共$m$个,由于有$1$~$3$所以每位计算时都要减一,也就是每次计算$s*3+(now-1)$。

然后把所有可行状态算出存在$p$数组中,共$tot$个。

关于怎么算提供一个技巧,就是十进制下$x$进制(假设为$a$)的倒数第$k$位是$(a/x^k)\%x$。

注意进制是从0位开始到m-1结束。

记得初始化:

先是$memset(f,0,sizeof(f));$

  • 若$k==1$ $f[1][s]=1;$
  • 若$k!=1$ $for (int i=1;i<=tot;i++) f[1][p[i]]=1;$

计算

也就是转移状态。

分两种,一种是当前行为$k$的,一种是不为$k$的,枚举第$i$行,上行状态为$j$,此行状态为$k$,判断上行是否与此行冲突即可。

方程如下:

  • 若$i!=k$ $f[i][p[j]]+=f[i-1][p[k]];$
  • 若$i==k$ $f[i][s]+=f[i-1][p[j]];f[i][s]\%=Mod;$

最后把第$n$行所有状态累加$Mod$即可。

注意点

  1. 还记得十进制下$x$进制(假设为$a$)的倒数第$k$位是$(a/x^k)\%x$这个方法吗?其实你可以把状态全部颠倒算,这样就不用管倒数的事了。
  2. 还有就是第$k$行可能无解,记得特判一下。

代码

 1 #include<bits/stdc++.h>
 2 #define Mod 1000000
 3 using namespace std;
 4 int n,m,k,s;
 5 int lg[10];
 6 int f[10005][250];
 7 int p[250],tot=0;
 8 void screen(int x)
 9 {
10     for (int i=0;i<=lg[x]-1;i++) 
11     {
12         bool flag=0;
13         for (int j=0;j<=m-2;j++)    
14             if ((i/lg[j])%3==(i/lg[j+1])%3) {flag=1;break;}
15         if (flag==0) p[++tot]=i;
16     }
17 }
18 bool check(int a,int b)
19 {
20     for (int i=0;i<=m-1;i++) if ((a/lg[i])%3==(b/lg[i])%3) return 0;
21     return 1;
22 }
23 int main()
24 {
25     s=0;lg[0]=1;
26     scanf("%d%d%d",&n,&m,&k);
27     for (int i=1;i<=m;i++) 
28     {    
29         int x;
30         scanf("%d",&x);
31         s=s*3+(x-1); lg[i]=lg[i-1]*3;
32     }
33     screen(m);
34     bool flag=0;
35     //for (int i=1;i<=tot;i++) cout<<p[i]<<endl;
36     for (int i=1;i<=tot;i++) if (p[i]==s) flag=1;
37     if (flag==0) {cout<<0<<endl;return 0;}
38     memset(f,0,sizeof(f));
39     if (k==1) f[1][s]=1;
40     else for (int i=1;i<=tot;i++) f[1][p[i]]=1;
41     for (int i=2;i<=n;i++)
42     {
43         if (i!=k)
44         {
45             for (int j=1;j<=tot;j++)
46             {
47                 for (int k=1;k<=tot;k++)
48                 {
49                 if (check(p[j],p[k])) f[i][p[j]]+=f[i-1][p[k]];
50                 f[i][p[j]]%=Mod;
51                 }
52             }
53         }
54         if (i==k)
55         {
56             for (int j=1;j<=tot;j++) if (check(p[j],s)) f[i][s]+=f[i-1][p[j]];
57             f[i][s]%=Mod;
58         }
59     }
60     int ans=0;
61     for (int i=1;i<=tot;i++) ans+=f[n][p[i]],ans%=Mod;
62     cout<<ans<<endl;
63     return 0;
64 }

猜你喜欢

转载自www.cnblogs.com/GaryFang/p/11042806.html
今日推荐