• #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;
    }

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

  • 相关阅读:
    FZU Problem 2169 shadow
    tomcat配置虚拟主机
    数据库设计中的14个技巧
    JSP动作--JSP有三种凝视方式
    BoundsChecker使用
    个人收藏的flex特效网址【经典中的极品】
    C++中的explicitkeyword
    Andorid Binder进程间通信---Binder本地对象,实体对象,引用对象,代理对象的引用计数
    深入浅出JMS(一)——JMS简单介绍
    一个有意思的编程练习站点
  • 原文地址:https://www.cnblogs.com/sky-zxz/p/9865604.html
Copyright © 2020-2023  润新知