#3880 涂抹果酱
鬼知道为什么我卡了那么久
题面
yvj 两周年庆典要到了,Sam 想为 Tyvj 做一个大蛋糕。蛋糕俯视图是一个 N×M 的矩形,它被划分成 N×M 个边长为 1×1 的小正方形区域(可以把蛋糕当成 N 行 M 列的矩阵)。蛋糕很快做好了,但光秃秃的蛋糕肯定不好看!所以,Sam 要在蛋糕的上表面涂抹果酱。果酱有三种,分别是红果酱、绿果酱、蓝果酱,三种果酱的编号分别为 1,2,3。为了保证蛋糕的视觉效果,Admin 下达了死命令:相邻的区域严禁使用同种果酱。但 Sam 在接到这条命令之前,已经涂好了蛋糕第 K 行的果酱,且无法修改。
现在 Sam 想知道:能令 Admin 满意的涂果酱方案有多少种。请输出方案数 mod 10^6。若不存在满足条件的方案,请输出 0。
输入
输入共三行。
第一行:N,M
第二行:K;
第三行:M 个整数,表示第 K行的方案。
字母的详细含义见题目描述,其他参见样例。
输出
输出仅一行,为可行的方案总数。
样例输入
2 2
1
2 3
样例输出
3
提示
样例说明
方案一
2 3
1 2
方案二
2 3
3 1
方案三
2 3
3 2
对于 30% 的数据,
1
≤
N
×
M
≤
20
1≤N×M≤20
1≤N×M≤20;
对于 60% 的数据,
1
≤
N
≤
1000
,
1
≤
M
≤
3
1≤N≤1000,1≤M≤3
1≤N≤1000,1≤M≤3;
对于 100% 的数据,
1
≤
N
≤
10000
,
1
≤
M
≤
5
1≤N≤10000,1≤M≤5
1≤N≤10000,1≤M≤5。
SOL
读完题后可以得知,每个格子只看有三种状态,即三种颜色,于是将题目转成三进制来做就好。
三进制的比较并不是很难,逐个比较每一位就好了(只是函数写法不要太皮)。
其实这道题最关键的是如何处理第k行。
思考后可以发现,将网格划分为k行以上、k行一下的2个部分,然后k位首行初始化,最后通过乘法原理处理一下就好了。
此外,这道题容易超时,因此我建议所有状态都预处理。
注意细节。
代码:
#include<bits/stdc++.h>
#define int long long
#define N 10005
#define M 250
using namespace std;
inline int rd(){
int register data=0;static char ch=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))data=(data<<1)+(data<<3)+ch-'0',ch=getchar();
return data;
}
inline void write(int x){if(x>9)write(x/10);putchar(x%10+'0');}
int n,m,k,f[N][M],s[M],ok[M][M],c[6],cnt;
const int mod=1e6;
inline int und(int x,int y){for(int register i=m-1;i>=0;--i) if((x%c[i+1])/c[i]==(y%c[i+1])/c[i]) return 0;return 1;}
inline int umd(int x){for(int register i=m-1;i;--i)if((x%c[i+1])/c[i]==(x%c[i])/c[i-1]) return 0;return 1;}
signed main(){
n=rd();m=rd();k=rd();c[0]=1;for(int register a=1;a<=m;a++)c[a]=c[a-1]*3;
int register tmp=0;
for(int register i=1;i<=m;i++){tmp=tmp*3+rd()-1;}
if(!umd(tmp)){putchar('0');return 0;}
for(int register i=0;i<c[m];i++){
if(!umd(i))continue;
s[++cnt]=i;
if(i==tmp)f[0][cnt]=1;
}
for(int register i=1;i<=cnt;i++)for(int register j=1;j<=cnt;j++)ok[i][j]=und(s[i],s[j]);
int register mn=min(n-k,k-1),mx=max(n-k,k-1);
for(int register i=1;i<=mx;i++){
for(int register j=1;j<=cnt;j++){
if(!f[i-1][j])continue;
for(int register k=1;k<=cnt;k++){
if(!ok[k][j])continue;
f[i][k]=(f[i][k]+f[i-1][j])%mod;
}
}
}
int register ans1=0,ans2=0;
for(int register i=1;i<=cnt;i++)ans1=(ans1+f[mn][i])%mod,ans2=(ans2+f[mx][i]%mod);
write(ans1*ans2%mod);
return 0;
}