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。

样例输入(点击右上角复制按钮 即可复制)

2 2
1
2 3

样例输出

3

因为数据范围中很小,可以想到是状态压缩,而且毫无疑问地会选择压缩每一行。

因为这道题中有3种需要进行区分的果酱,所以使用三进制压缩,分别用0、1、2来表示。

然后按照普通的状压DP枚举每一行,进行合法方案数上的转移即可。

并且可以考虑预处理来优化:

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

    e.g: m=3时,枚举了状态 111 或 000 或 222,显然,这样是没有必要的。

    这就需要预处理出一行中的可行状态。经过统计,可以发现,即便是m=5,一行中的合法状态也只有48种,姑且当作50吧。

2. 在DP时,并不需要将每一种状态对应的十进制记录出来,更省空间且更简便的做法是:在储存时编号,这样就可以在遍历上一行和当前行的状态时直接取编号  ->这也是状压DP的常见套路了吧

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

    使得时间复杂度有很高的保证。

总体最高时间复杂度为 (也有粗略的四舍五入啊)大概250万的样子

细节问题也要注意啊:在运算过程中也有溢出的可能性

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 10006
#define mod 1000000
using namespace std;inline int wread(){char c=getchar ();int flag=1,wans=0;while (c<'0'||c>'9'){if (c=='-') flag=-1;c=getchar ();}while (c>='0'&&c<='9'){wans=wans*10+c-'0';c=getchar ();}return wans*=flag;
}int n,m;int thre[250];//3^i的值
int lin_cal[5];//临时存储
int cal[50][5],top_cal;//每一种合法状态的每一位的数字  合法状态用编号储存
int pre[50];//取出合法的状态
int bel[250];
//三进制处理
void getthree(int x){thre[0]=1;for (int i=1;i<=x;++i)thre[i]=thre[i-1]*3;for (int i=0;i<thre[x];++i){//不能取等 int nx=i,top_wei=0;while (nx)  {lin_cal[++top_wei]=nx%3;nx/=3;}bool Jud=true;for (int j=2;j<=x;++j)if (lin_cal[j]==lin_cal[j-1]) {Jud=false;break;}if (!Jud)    continue;++top_cal;pre[top_cal]=i;bel[i]=top_cal;for (int j=1;j<=x;++j){cal[top_cal][j]=lin_cal[j];}}
}bool jud[50][50];
//预处理 判断
void getjud (){for (int i=1;i<=top_cal;++i){jud[i][i]=false;for (int j=i+1;j<=top_cal;++j){bool Jud=true;for (int k=1;k<=m;++k){if (cal[i][k]==cal[j][k]) {Jud=false;break;}}if (!Jud)   jud[i][j]=jud[j][i]=false;else jud[i][j]=jud[j][i]=true;}}
}int made_l,l_zh;
int dp[N][50];int main (){n=wread();m=wread();getthree(m);getjud();made_l=wread();for (int i=1;i<=m;++i){lin_cal[i]=wread();lin_cal[i]--;l_zh+=lin_cal[i]*thre[m-i];}if (!bel[l_zh])   {puts("0");return 0;}if (made_l==1) {dp[1][bel[l_zh]]=1;for (int A=2;A<=n;++A)for (int i=1;i<=top_cal;++i)   //这一行状态 for (int j=1;j<=top_cal;++j) //上一行状态 if (jud[i][j])  dp[A][i]=(dp[A-1][j]%mod+dp[A][i]%mod)%mod;int ans=0;for (int i=1;i<=top_cal;++i)ans=(ans%mod+dp[n][i]%mod)%mod;printf("%d\n",ans);}else {for (int i=1;i<=top_cal;++i)dp[1][i]=1;for (int A=2;A<=n;++A){if (A==made_l){for (int j=1;j<=top_cal;++j)if (jud[bel[l_zh]][j]) dp[A][bel[l_zh]]=(dp[A-1][j]%mod+dp[A][bel[l_zh]]%mod)%mod;continue;}for (int i=1;i<=top_cal;++i)//这一行的状态 for (int j=1;j<=top_cal;++j)//上一行的状态 if (jud[i][j])   dp[A][i]=(dp[A-1][j]%mod+dp[A][i]%mod)%mod;}int ans=0;for (int i=1;i<=top_cal;++i)ans=(ans%mod+dp[n][i]%mod)%mod;printf("%d\n",ans);}return 0;
}

#10172. 「一本通 5.4 练习 1」涂抹果酱 【 三进制状态压缩 】【 方案数 】相关推荐

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

    题目链接:https://loj.ac/problem/10172 题目描述 Tyvj 两周年庆典要到了,Sam 想为 Tyvj 做一个大蛋糕.蛋糕俯视图是一个 N×MN×MN×M 的矩形,它被划分成 ...

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

    题目链接 一道三进制状压的好题. 题目描述: Tyvj 两周年庆典要到了,Sam 想为 Tyvj 做一个大蛋糕.蛋糕俯视图是一个 N×M的矩形,它被划分成 N×M个边长为 1×1的小正方形区域(可以把 ...

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

    题目描述 Tyvj 两周年庆典要到了,Sam 想为 Tyvj 做一个大蛋糕.蛋糕俯视图是一个 N×M 的矩形,它被划分成 N×M 个边长为 1×1 的小正方形区域(可以把蛋糕当成 NNN 行 MMM  ...

  4. 「一本通 6.5 练习 3」迷路

    「一本通 6.5 练习 3」迷路 题目描述 大意说一个给你有向图, 一个有n个节点,每个节点相连的边为所需要花费的时间, 问你从1到n 在时间刚好为t是的方案数.输出%2009 注意:不能在某个节点逗 ...

  5. 【C++】「一本通 1.1 例 4」加工生产调度

    「一本通 1.1 例 4」加工生产调度 [来源] [题目描述] [输入格式] [输出格式] [输入样例] [输出样例] [数据范围] [解析] [代码] [来源] 一本通题库-1425 LibreOJ ...

  6. LibreOJ10082. 「一本通 3.3 例 1」Word Rings【二分+SPFA】

    10082. 「一本通 3.3 例 1」Word Rings [题目描述] 传送门 [题解] 将一个字符串看成一条边,字符两端的字符看成节点,长度看成权值.二分枚举答案,最后SPFA刷正环,因为只要有 ...

  7. #10016. 「一本通 1.2 练习 3」灯泡(三分)

    参考博客链接:「一本通 1.2 练习 3」灯泡(三分) #include<stdio.h> #include<string.h> #include<math.h> ...

  8. 【C++】「一本通 1.1 例 2」种树

    「一本通 1.1 例 2」种树 [来源] [题目描述] [输入格式] [输出格式] [输入样例] [输出样例] [解析] [代码] [来源] 一本通题库-1423 LibreOJ-10001 vjud ...

  9. #10001. 「一本通 1.1 例 2」种树

    #10001. 「一本通 1.1 例 2」种树 满足n个区间种树的要求,求最少种多少棵数 思路 按照区间的尾巴来排序,因为如果区间有重叠的种在第一个区间的尾巴可以使得种树更少,所有每次始从尾巴开始种树 ...

最新文章

  1. python 2: 解决python中的plot函数的图例legend不能显示中文问题
  2. Maven 的获取、安装与环境变量设置方法
  3. CVE-2021-29454——Smarty模板注入
  4. 【328天】每日项目总结系列066(2017.12.30)
  5. 博客园添加一个分享的
  6. redis python 出错重连_python穿透类 对象代理
  7. JQuery插件,轻量级表单模型验证
  8. 车辆贷款违约预测 Top1(2021科大讯飞)
  9. Leetcode-树
  10. 公司内网与外网连通中的一些小问题(达内)
  11. 如何选择tomcat版本
  12. base64、File、Blob、ArrayBuffer互转
  13. 【Unity3D】 Unity Chan项目分享
  14. python 词云学习
  15. GeneXus笔记Excel导入
  16. phpcms 之 添加栏目时,输入英文栏目之后,总是提示栏目已存在
  17. 全自动过滤型射频水处理器工作原理
  18. LwIP学习笔记——STM32 ENC28J60移植与入门
  19. 洛咕11月月赛部分题解 By cellur925
  20. Freebase数据集介绍

热门文章

  1. 判断文档是office打开,还是WPS打开
  2. 拉格朗日乘子法、罚函数法、乘子罚函数法
  3. 深度解读《互联网信息服务算法推荐管理规定(征求意见稿)》 by 傅一平
  4. 漫画:怎样学习机器学习?
  5. js编码java解码_常用的js、java编码解码方法
  6. ux设计师薪水_UX初学者选择亲和力设计师而不是Adobe illustrator的3个节俭原因
  7. 【时钟识别】基于matlab GUI Hough变换指针式时钟识别【含Matlab源码 2085期】
  8. 淮阴工c语言期末考试卷子,淮阴工学院C语言期末
  9. 使用循环语句输出菱形图案
  10. Alios—Things操作系统