#10172. 「一本通 5.4 练习 1」涂抹果酱 题解

Posted sky-zxz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#10172. 「一本通 5.4 练习 1」涂抹果酱 题解相关的知识,希望对你有一定的参考价值。

题目链接

一道三进制状压的好题。

题目描述:

 

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

 

输入格式

输入共三行。
第一行:N,M
第二行:K
第三行:M 个整数,表示第 行的方案。
字母的详细含义见题目描述,其他参见样例。

输出格式

输出仅一行,为可行的方案总数。

样例

样例输入

2 2 
1 
2 3

样例输出

 3 

解题思路:

这道题关键在判断合法情况,第k行特判一下即可。

1.判断一个三进制数是否有相同数字相邻的情况,不能模拟二进制左移右移的情况,

因为这里有3个数字,左移右移会出现有0的影响。

2.判断不同行是否有相同数字相邻,模拟二进制的&判断一下即可。

代码:

 

#include<bits/stdc++.h>
#define ll long long 
#define R register
using namespace std;
int  n,m,k,mod=1e6,a[250],sk,num,top,ans,f[10005][250];
inline int ksm(R int x,R int p)
{
    R int tot=1;
    while(p)
    {
        if(p&1)
        {
        tot=tot*x;
        }
        x=x*x;
        p>>=1;
    }
    return tot;
}
inline int check(R int x,R int y)
{
    for(R int i=1;i<=m;++i){
        if((x%3)==(y%3))return 0;
        x/=3;
        y/=3;
    }
    return 1;
}
inline int judge(R int x)
{
    R int y=-1;
    for(R int i=1;i<=m;++i)
    {    
        if(y==x%3)return 0;
        y=x%3;
        x/=3;
    }
    return 1;
}
inline void init()
{
    for(R int i=0;i<=242;++i){
        R int x=i,tot=0;
        while(x)
        {
        x/=3;
        ++tot;
        }
        if(tot>=m+1)break;
        if(judge(i)){    
            a[++num]=i;    
            if(i==sk)top=num;
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    scanf("%d",&k);
    for(R int i=1;i<=m;++i)
    {
        R int t;
        scanf("%d",&t);
        sk+=(t-1)*ksm(3,i-1);
    }
    if(!judge(sk))    
    {
    printf("0");
    return 0;
    }
    init();
    if(k==1)
    f[1][top]=1;
    else
    for(R int i=1;i<=num;++i)
    f[1][i]=1;
    for(R int i=2;i<=n;++i)//当前第几行
    {
        if(i==k)
        {
            for(R int t=1;t<=num;++t)
            if(check(a[top],a[t]))
            f[i][top]=(f[i][top]+f[i-1][t])%mod;
        }
        else
        {
            for(R int j=1;j<=num;++j)//当前行状态
            {
                if(i-1==k)
                {
                    if(check(a[j],a[top]))
                    f[i][j]=(f[i][j]+f[i-1][top])%mod;
                }
                else
                {
                    for(R int t=1;t<=num;++t)//上一行状态
                    if(check(a[j],a[t]))
                    f[i][j]=(f[i][j]+f[i-1][t])%mod;
                }
            }
        }
    }
    for(R int i=1;i<=num;++i)
    ans=(ans+f[n][i])%mod;
    printf("%d",ans%mod);
    return 0;
}

 

这道题关键在于舍弃不合法情况的判断.

 

 

以上是关于#10172. 「一本通 5.4 练习 1」涂抹果酱 题解的主要内容,如果未能解决你的问题,请参考以下文章

信息学奥赛一本通 5.4 状态压缩动态规划

涂抹果酱

#10023. 「一本通 1.3 练习 2」平板涂色

「一本通 4.1 练习 2」简单题

loj10188. 「一本通 5.6 练习 1」玩具装箱

loj10150. 「一本通 5.1 练习 1」括号配对