#10172. 「一本通 5.4 练习 1」涂抹果酱 【 三进制状态压缩 】【 方案数 】
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」涂抹果酱 【 三进制状态压缩 】【 方案数 】相关推荐
- LOJ#10172. 「一本通 5.4 练习 1」涂抹果酱
题目链接:https://loj.ac/problem/10172 题目描述 Tyvj 两周年庆典要到了,Sam 想为 Tyvj 做一个大蛋糕.蛋糕俯视图是一个 N×MN×MN×M 的矩形,它被划分成 ...
- #10172. 「一本通 5.4 练习 1」涂抹果酱 题解
题目链接 一道三进制状压的好题. 题目描述: Tyvj 两周年庆典要到了,Sam 想为 Tyvj 做一个大蛋糕.蛋糕俯视图是一个 N×M的矩形,它被划分成 N×M个边长为 1×1的小正方形区域(可以把 ...
- LOJ #10172. 「一本通 5.4 练习 1」涂抹果酱
题目描述 Tyvj 两周年庆典要到了,Sam 想为 Tyvj 做一个大蛋糕.蛋糕俯视图是一个 N×M 的矩形,它被划分成 N×M 个边长为 1×1 的小正方形区域(可以把蛋糕当成 NNN 行 MMM ...
- 「一本通 6.5 练习 3」迷路
「一本通 6.5 练习 3」迷路 题目描述 大意说一个给你有向图, 一个有n个节点,每个节点相连的边为所需要花费的时间, 问你从1到n 在时间刚好为t是的方案数.输出%2009 注意:不能在某个节点逗 ...
- 【C++】「一本通 1.1 例 4」加工生产调度
「一本通 1.1 例 4」加工生产调度 [来源] [题目描述] [输入格式] [输出格式] [输入样例] [输出样例] [数据范围] [解析] [代码] [来源] 一本通题库-1425 LibreOJ ...
- LibreOJ10082. 「一本通 3.3 例 1」Word Rings【二分+SPFA】
10082. 「一本通 3.3 例 1」Word Rings [题目描述] 传送门 [题解] 将一个字符串看成一条边,字符两端的字符看成节点,长度看成权值.二分枚举答案,最后SPFA刷正环,因为只要有 ...
- #10016. 「一本通 1.2 练习 3」灯泡(三分)
参考博客链接:「一本通 1.2 练习 3」灯泡(三分) #include<stdio.h> #include<string.h> #include<math.h> ...
- 【C++】「一本通 1.1 例 2」种树
「一本通 1.1 例 2」种树 [来源] [题目描述] [输入格式] [输出格式] [输入样例] [输出样例] [解析] [代码] [来源] 一本通题库-1423 LibreOJ-10001 vjud ...
- #10001. 「一本通 1.1 例 2」种树
#10001. 「一本通 1.1 例 2」种树 满足n个区间种树的要求,求最少种多少棵数 思路 按照区间的尾巴来排序,因为如果区间有重叠的种在第一个区间的尾巴可以使得种树更少,所有每次始从尾巴开始种树 ...
最新文章
- python 2: 解决python中的plot函数的图例legend不能显示中文问题
- Maven 的获取、安装与环境变量设置方法
- CVE-2021-29454——Smarty模板注入
- 【328天】每日项目总结系列066(2017.12.30)
- 博客园添加一个分享的
- redis python 出错重连_python穿透类 对象代理
- JQuery插件,轻量级表单模型验证
- 车辆贷款违约预测 Top1(2021科大讯飞)
- Leetcode-树
- 公司内网与外网连通中的一些小问题(达内)
- 如何选择tomcat版本
- base64、File、Blob、ArrayBuffer互转
- 【Unity3D】 Unity Chan项目分享
- python 词云学习
- GeneXus笔记Excel导入
- phpcms 之 添加栏目时,输入英文栏目之后,总是提示栏目已存在
- 全自动过滤型射频水处理器工作原理
- LwIP学习笔记——STM32 ENC28J60移植与入门
- 洛咕11月月赛部分题解 By cellur925
- Freebase数据集介绍