zoukankan      html  css  js  c++  java
  • LOJ#10172. 「一本通 5.4 练习 1」涂抹果酱

    题目链接:https://loj.ac/problem/10172

    题目描述

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

    输入格式

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

    输出格式

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

    样例

    样例输入

    2 2 
    1 
    2 3

    样例输出

    3

    样例说明

    方案一方案二方案三
    2 3 exttt{2 3}2 3 
    1 2 exttt{1 2}1 2
    2 3 exttt{2 3}2 3 
    3 1 exttt{3 1}3 1
    2 3 exttt{2 3}2 3 
    3 2 exttt{3 2}3 2

    数据范围与提示

    对于 30% 的数据,1≤N×M≤201≤N×M≤201N×M20;
    对于 60% 的数据,1≤N≤1000,1≤M≤31≤N≤1000,1≤M≤31N1000,1M3;
    对于 100% 的数据,1≤N≤10000,1≤M≤51≤N≤10000,1≤M≤51N10000,1M5。

    题解

    在网上找的题解,都不太清楚,让本蒟蒻卡了一下午加一晚上。

    所以我弄懂以后,我就自己写了一篇,希望大家喜欢!

    这道题是一道很好的状态压缩dp,因为有三种颜色,所以不能压成二进制,只能压成三进制。

    当然啦,状压dp是基本一定要初始化的,别问我怎么知道的。

    我们考虑以下两个初始化(就是代码里的pd1,pd2

    1. 每一行总共有很多种,但是因为相同颜色的果酱不能放在相邻的位置,所以每一行的不可行状态有很多。

        这就需要预处理出一行中的可行状态。这样的话我们的dp数量会大大减少。

    3. 预处理行与行之间的判断

        跟预处理类似,减去不合法状态。

    然后,就是我们的dp了。

    其实这题很好想,dp[i][j]表示第i行的第j种状态,最后取个摸就行了。

    方程:dp[i][j]+=dp[i-1][k]

    最后的最后,大力推荐一下我的读入优化,跑的是真滴快!

    #define num ch-'0'
    inline void get(int &res)
    {
        char ch;bool flag=0;
        while(!isdigit(ch=getchar()))
            (ch=='-')&&(flag=true);
        for(res=num;isdigit(ch=getchar());res=res*10+num);
        (flag)&&(res=-res);
    }

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #define MAXN 10010
    #define mod 1000000
    #define num ch-'0'
    using namespace std;
    inline int MAX(int a,int b){return a>b?a:b;}
    inline int MIN(int a,int b){return a<b?a:b;}
    inline void get(int &res)
    {
        char ch;bool flag=0;
        while(!isdigit(ch=getchar()))
            (ch=='-')&&(flag=true);
        for(res=num;isdigit(ch=getchar());res=res*10+num);
        (flag)&&(res=-res);
    }
    int n,g,m,k;
    int dp[MAXN][250],ok[250][250];
    int a[250],c[7],t;
    inline int pd1(int x)
    {
        for(register int i=m-1;i;--i)if((x%c[i+1])/c[i]==(x%c[i])/c[i-1]) return 0;
        return 1;
    }
    inline int pd2(int x,int y)
    {
        for(register int i=m-1;i>=0;--i) if((x%c[i+1])/c[i]==(y%c[i+1])/c[i]) return 0;
        return 1;
    }
    int main()
    {
        get(n),get(m),get(k);
        c[0]=1;
        int num1=0;
        for(register int i=1;i<=m;++i) 
        {
            get(g);
            num1=num1*3+(g-1);
            c[i]=c[i-1]*3;
        }        
        if(!pd1(num1)) {puts("0");return 0;}
        for(register int i=0;i<c[m];++i)
        {
            if(pd1(i)) a[++t]=i;
            if(num1==i) dp[0][t]=1;
        }
        for(register int i=1;i<=t;++i) 
          for(register int j=1;j<=t;++j) 
            ok[i][j]=pd2(a[i],a[j]);
        int res1=0,res2=0;
        int x=MIN(n-k,k-1),y=MAX(n-k,k-1);
        for(register int i=1;i<=y;++i) 
          for(register int j=1;j<=t;++j) 
            for(register int k=1;k<=t;++k) 
              if(ok[k][j]) 
                (dp[i][j]+=dp[i-1][k])%=mod;
        for(register int i=1;i<=t;++i) 
        {
            res1=(res1+dp[x][i])%mod;
            res2=(res2+dp[y][i])%mod;
        }        
        printf("%lld",((long long)res2*res1)%mod);
    }
  • 相关阅读:
    通配符函数 MatchesMask 的使用
    WinAPI: GetComputerName 获取计算机名称
    TStringList 常用操作
    分割字符串 ExtractStrings
    磁盘类型 GetDriveType
    Delphi 的信息框相关函数
    Delphi 的运算符列表
    类型转换函数
    文件路径相关的字符串操作
    澳洲技术移民介绍
  • 原文地址:https://www.cnblogs.com/mxrmxr/p/9807067.html
Copyright © 2011-2022 走看看