Loj10172 涂抹果酱
题目描述
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。
这道题用状压DP,是三维的,有很多细节要注意处理。
其中我用了比较笨的储存方法,但是能有效地忽略掉特殊行。
具体看代码,不懂评论。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cstdlib> #include <queue> #include <stack> #include <vector> using namespace std; #define MAXN 100010 #define INF 10000009 #define MOD 1000000 #define LL long long #define in(a) a=read() #define REP(i,k,n) for(int i=k;i<=n;i++) #define DREP(i,k,n) for(int i=k;i>=n;i--) #define cl(a) memset(a,0,sizeof(a)) inline int read(){ int x=0,f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } inline void out(int x){ if(x<0) putchar('-'),x=-x; if(x>9) out(x/10); putchar(x%10+'0'); } int n,m,k; int pow[110]; LL f[10010][250]; struct node{ LL num,a[250]; }tree[10010]; bool check1(int a,int b){ int sa[6],sb[6],na=m+1,nb=m+1; memset(sa,0,sizeof(sa)); memset(sb,0,sizeof(sb)); while(a){ sa[--na]=a%3; a/=3; } while(b){ sb[--nb]=b%3; b/=3; } REP(i,1,m){ //cout<<sa[i]<<" "<<sb[i]<<endl; if(sa[i]==sb[i]) return false;} return true; } bool check2(int a){ int sa[6],na=m+1; memset(sa,0,sizeof(sa)); while(a){ sa[--na]=a%3; a/=3; } REP(i,2,m) if(sa[i]==sa[i-1]) return false; return true; } void init(){ REP(i,1,n){ if(i==k) continue; tree[i].num=0; REP(j,0,pow[m]-1) if(check2(j)){ tree[i].a[++tree[i].num]=j; } } return ; } int DP(){ LL ans=0; REP(i,1,tree[1].num) f[1][i]=1; REP(i,2,n) REP(j,1,tree[i].num) REP(k,1,tree[i-1].num) if(check1(tree[i].a[j],tree[i-1].a[k])) { f[i][j]=(f[i][j]+f[i-1][k])%MOD; } REP(i,1,tree[n].num) ans=(ans+f[n][i])%MOD; return ans; } int main(){ pow[0]=1; REP(i,1,10) pow[i]=pow[i-1]*3; in(n);in(m);in(k); tree[k].num=1; REP(i,1,m){ int x; in(x); x-=1; tree[k].a[1]+=x*pow[m-i]; } if(!check2(tree[k].a[1])){ cout<<0; return 0; } init(); /*REP(i,1,n){ REP(j,1,tree[i].num) cout<<tree[i].a[j]<<" "; cout<<endl; }*/ cout<<DP()<<endl; /*REP(i,1,n){ REP(j,1,tree[i].num) cout<<f[i][j]<<" "; cout<<endl; }*/ return 0; }