zoukankan      html  css  js  c++  java
  • 涂抹果酱

    题面

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

    思路

    我们设$f[i][j]$表示第$i$行状态为$j$时的方案数。

    预处理

    先读入数据,在读入过程中将$3^1$~$3^m$算出,用$lg[i]$表示$3^i$。

    然后压缩指定行$k$的状态$s$,初始$s=0$,$now$为当前位置上的数,共$m$个,由于有$1$~$3$所以每位计算时都要减一,也就是每次计算$s*3+(now-1)$。

    然后把所有可行状态算出存在$p$数组中,共$tot$个。

    关于怎么算提供一个技巧,就是十进制下$x$进制(假设为$a$)的倒数第$k$位是$(a/x^k)\%x$。

    注意进制是从0位开始到m-1结束。

    记得初始化:

    先是$memset(f,0,sizeof(f));$

    • 若$k==1$ $f[1][s]=1;$
    • 若$k!=1$ $for (int i=1;i<=tot;i++) f[1][p[i]]=1;$

    计算

    也就是转移状态。

    分两种,一种是当前行为$k$的,一种是不为$k$的,枚举第$i$行,上行状态为$j$,此行状态为$k$,判断上行是否与此行冲突即可。

    方程如下:

    • 若$i!=k$ $f[i][p[j]]+=f[i-1][p[k]];$
    • 若$i==k$ $f[i][s]+=f[i-1][p[j]];f[i][s]\%=Mod;$

    最后把第$n$行所有状态累加$Mod$即可。

    注意点

    1. 还记得十进制下$x$进制(假设为$a$)的倒数第$k$位是$(a/x^k)\%x$这个方法吗?其实你可以把状态全部颠倒算,这样就不用管倒数的事了。
    2. 还有就是第$k$行可能无解,记得特判一下。

    代码

     1 #include<bits/stdc++.h>
     2 #define Mod 1000000
     3 using namespace std;
     4 int n,m,k,s;
     5 int lg[10];
     6 int f[10005][250];
     7 int p[250],tot=0;
     8 void screen(int x)
     9 {
    10     for (int i=0;i<=lg[x]-1;i++) 
    11     {
    12         bool flag=0;
    13         for (int j=0;j<=m-2;j++)    
    14             if ((i/lg[j])%3==(i/lg[j+1])%3) {flag=1;break;}
    15         if (flag==0) p[++tot]=i;
    16     }
    17 }
    18 bool check(int a,int b)
    19 {
    20     for (int i=0;i<=m-1;i++) if ((a/lg[i])%3==(b/lg[i])%3) return 0;
    21     return 1;
    22 }
    23 int main()
    24 {
    25     s=0;lg[0]=1;
    26     scanf("%d%d%d",&n,&m,&k);
    27     for (int i=1;i<=m;i++) 
    28     {    
    29         int x;
    30         scanf("%d",&x);
    31         s=s*3+(x-1); lg[i]=lg[i-1]*3;
    32     }
    33     screen(m);
    34     bool flag=0;
    35     //for (int i=1;i<=tot;i++) cout<<p[i]<<endl;
    36     for (int i=1;i<=tot;i++) if (p[i]==s) flag=1;
    37     if (flag==0) {cout<<0<<endl;return 0;}
    38     memset(f,0,sizeof(f));
    39     if (k==1) f[1][s]=1;
    40     else for (int i=1;i<=tot;i++) f[1][p[i]]=1;
    41     for (int i=2;i<=n;i++)
    42     {
    43         if (i!=k)
    44         {
    45             for (int j=1;j<=tot;j++)
    46             {
    47                 for (int k=1;k<=tot;k++)
    48                 {
    49                 if (check(p[j],p[k])) f[i][p[j]]+=f[i-1][p[k]];
    50                 f[i][p[j]]%=Mod;
    51                 }
    52             }
    53         }
    54         if (i==k)
    55         {
    56             for (int j=1;j<=tot;j++) if (check(p[j],s)) f[i][s]+=f[i-1][p[j]];
    57             f[i][s]%=Mod;
    58         }
    59     }
    60     int ans=0;
    61     for (int i=1;i<=tot;i++) ans+=f[n][p[i]],ans%=Mod;
    62     cout<<ans<<endl;
    63     return 0;
    64 }
  • 相关阅读:
    Leetcode-Pascal's Triangle
    SRM 619
    请用漂亮欢呼-------Day38
    创建list方法总结
    [ZJOI2019]语言
    jekyll 在博客添加流程图
    jekyll 在博客添加流程图
    HttpRepl 互操作的 RESTful HTTP 服务调试命令行工具
    HttpRepl 互操作的 RESTful HTTP 服务调试命令行工具
    How to use code to exit the application in UWP
  • 原文地址:https://www.cnblogs.com/GaryFang/p/11042806.html
Copyright © 2011-2022 走看看