题目描述
Tyvj 两周年庆典要到了,Sam 想为 Tyvj 做一个大蛋糕。蛋糕俯视图是一个 N×M 的矩形,它被划分成 N×M 个边长为 1×1 的小正方形区域(可以把蛋糕当成 NNN 行 MMM 列的矩阵)。蛋糕很快做好了,但光秃秃的蛋糕肯定不好看!所以,Sam 要在蛋糕的上表面涂抹果酱。果酱有三种,分别是红果酱、绿果酱、蓝果酱,三种果酱的编号分别为 1,2,31,2,31,2,3。为了保证蛋糕的视觉效果,Admin 下达了死命令:相邻的区域严禁使用同种果酱。但 Sam 在接到这条命令之前,已经涂好了蛋糕第 KKK 行的果酱,且无法修改。
现在 Sam 想知道:能令 Admin 满意的涂果酱方案有多少种。请输出方案数 mod106。若不存在满足条件的方案,请输出 000。
输入格式
输入共三行。
第一行:N,MN, MN,M;
第二行:KKK;
第三行:MMM 个整数,表示第 KKK 行的方案。
字母的详细含义见题目描述,其他参见样例。
输出格式
输出仅一行,为可行的方案总数。
样例
样例输入
2 2
1
2 3
样例输出
3
样例说明
方案一 | 方案二 | 方案三 |
---|---|---|
2 3 1 2 | 2 3 3 1 | 2 3 3 2 |
数据范围与提示
对于 30% 的数据,1≤N×M≤20;
对于 60% 的数据,1≤N≤1000,1≤M≤3;
对于 100% 的数据,1≤N≤10000,1≤M≤5。
因为有3种果酱,所以用三进制表示,用dfs生成状态
状态不超过100
#include<cstdio>
#define ll long long
#include<iostream>
const int p=1e6;
using namespace std;
inline int read()
{
int ret=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
return ret;
}
int n,m,k,cnt;
const int N=1e4+4,M=6,S=105;
int a[S],mi[M],c[M],f[N][S];
inline bool check(int x,int y)
{
int i=0;
while(x||y)
{
i++;
if(x%3==y%3) return 0;
x/=3,y/=3;
}
if(i<m) return 0;
return 1;
}
void dfs(int t,int s)
{
if(t>m)
{
a[++cnt]=s;
return;
}
if(s/mi[t-2]!=0) dfs(t+1,s);
if(s/mi[t-2]!=1) dfs(t+1,s+mi[t-1]);
if(s/mi[t-2]!=2) dfs(t+1,s+mi[t-1]+mi[t-1]);
}
int main()
{
n=read(),m=read(),k=read();
mi[0]=1;
for(int i=1;i<=m;i++) mi[i]=(mi[i-1]<<1)+mi[i-1];
dfs(2,0); dfs(2,1); dfs(2,2);
int x=0,loc=0;
for(int i=1;i<=m;i++)
x+=(read()-1)*mi[i-1];
for(int i=1;i<=cnt;i++)
if(a[i]==x)
{
loc=i; break;
}
if(!loc)
{
printf("0\n",0);
return 0;
}
f[1][loc]=1;
for(int i=2;i<=max(k,n-k+1);i++)
for(int j=1;j<=cnt;j++)
for(int k=1;k<=cnt;k++)
if(check(a[j],a[k])) f[i][j]=(f[i][j]+f[i-1][k])%p;
int ans=0;
for(int i=1;i<=cnt;i++) ans=(ans+f[k][i])%p;
int ss=0;
for(int i=1;i<=cnt;i++) ss=(ss+f[n-k+1][i])%p;
ans=(ll)ans*ss%p;
printf("%d\n",ans);
return 0;
}