E2. Rubik‘s Cube Coloring (hard version) dp,满二叉树(2300)
题意 :
- 其他条件和上题相同
- 这里已知n个点,给定每个点的编号和颜色
- 求这个树的合法染色方案,取模1e9 + 7
思路 :
- 首先预处理d[c][k]d[c][k]d[c][k]表示根结点颜色为c,深度为k的满二叉树的方案
- 0 <= c < 6, 1 <= k <= 60,数据范围较小,因此可以很快预处理
- 如果一颗子树,所有点都没有颜色,那么可以用预处理的数组直接O(1)O(1)O(1)给出方案数
- 因此我们只需要关注有带色点的子树
- 由于只有2000个点有颜色,k<=60,因此最多2000*60个点是我们需要关注的
- 我们对这2000*60个点单独记忆化搜索即可
- d2[id][c]d2[id][c]d2[id][c]表示id点颜色为c,子树的方案数
- d[][]d[][]d[][]和d2[][]d2[][]d2[][]的转移 :
- 枚举左右子结点的颜色即可
- 注意思考为什么需要映射
#include <iostream>
#include <cstring>
#include <map>using namespace std;typedef long long ll;const ll mod = 1e9 + 7;ll n, k;
ll lim[10][10];
ll d[10][66]; // 根结点颜色为c,层数为k的满二叉树方案数
ll d2[2222 * 66][6]; // i点颜色为j的子树的方案数
map<ll, ll> col;
map<ll, bool> mark; // 标记子树中至少有一个点已知颜色的点
map<ll, ll> idx;
ll num;// 颜色和数字的映射
map<char, ll> c_mp = {{'w', 0},{'y', 1},{'g', 2},{'b', 3},{'r', 4},{'o', 5},
};
/*
0是白 白黄
1是黄 白黄
2是绿 绿蓝
3是蓝 绿蓝
4是红 红橙
5是橙 红橙
*/// 对lim数组(两个颜色不能相邻)进行初始化
void init()
{lim[0][0] = lim[0][1] = 1;lim[1][0] = lim[1][1] = 1;lim[2][3] = lim[2][2] = 1;lim[3][2] = lim[3][3] = 1;lim[4][5] = lim[4][4] = 1;lim[5][4] = lim[5][5] = 1;
}// 颜色,层数
ll dp_dfs(ll c, ll k)
{if (k == 1) return 1; // 最后一层(注意这种倒过来表示层数的方法if (d[c][k] != -1) return d[c][k]; // 记忆化搜索d[c][k] = 0; // 开始累加方案for (int i = 0; i < 6; i ++ ) // 左儿子{if (lim[c][i]) continue; // 这种颜色方案不合法for (int j = 0; j < 6; j ++ ) // 右儿子{if (lim[c][j]) continue;// 该子树的根结点颜色为c,且这个根结点位于层数k,子树的方案// 子树的方案就是累加左右子树 相乘 的结果d[c][k] = (d[c][k] + dp_dfs(i, k - 1) * dp_dfs(j, k - 1) % mod) % mod;}}return d[c][k]; // 返回结果
}// 当前根结点的颜色,当前根结点的层数,当前根结点的编号
ll dfs(ll c, ll k, ll id)
{if (col.count(id) && col[id] != c) return 0; // 如果当前根结点已知颜色且颜色不是c,则这种方案不合法if (k == 1) return 1; // 最后一层// 如果子树中所有点都没有颜色,直接返回预处理的结果if (!mark[id]) return d[c][k];// 如果至少有一个子结点有颜色,则记忆化搜索if (!idx.count(id)) idx[id] = ++ num; // 如果这个点没有被访问过,更新映射ll x = idx[id]; // 获取映射后的下标if (d2[x][c] != -1) return d2[x][c]; // 记忆化搜索d2[x][c] = 0; // 访问到了这个状态,开始给这个状态累加答案ll l = id << 1, r = id << 1 | 1; // 左右儿子,注意这里是用编号,而不是映射for (int i = 0; i < 6; i ++ ){if (lim[c][i]) continue;for (int j = 0; j < 6; j ++ ){if (lim[c][j]) continue;d2[x][c] = (d2[x][c] + dfs(i, k - 1, l) * dfs(j, k - 1, r) % mod) % mod;}}return d2[x][c];
}void solve()
{init(); // 初始化不能相邻的颜色cin >> k >> n;// 初始化,-1表示未曾访问这种方案(记忆化搜索)memset(d, -1, sizeof d);memset(d2, -1, sizeof d2);// 子树中没有一个结点有颜色,for (int i = 0; i < 6; i ++ )dp_dfs(i, k);// n个有颜色的点for (int i = 1; i <= n; i ++ ){ll x; string s;cin >> x >> s;col[x] = c_mp[s[0]]; // id到颜色的映射while (x) // O(logn)标记所有祖先结点,这些祖先结点的子树都有有颜色的点{mark[x] = 1;x /= 2;}}ll ans = 0;for (int i = 0; i < 6; i ++ )ans = (ans + dfs(i, k, 1)) % mod;// 方案累加,【颜色,层数,编号】cout << ans << endl;
}int main()
{ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);int _ = 1;
// cin >> _;while (_ -- ){solve();}return 0;
}
E2. Rubik‘s Cube Coloring (hard version) dp,满二叉树(2300)相关推荐
- E1. Rubik‘s Cube Coloring (easy version) 贪心,满二叉树(1300)
题意 : 给定一个层数为k的满二叉树,结点编号为标准的层序遍历的编号 魔方有六个面,如图,每个面一个颜色 树上的结点的颜色也是这六个颜色之一,但是两个相邻结点的颜色必须是 魔方中,颜色相邻的两种颜色 ...
- Codeforces Round #617 (Div. 3) E2. String Coloring (hard version) 思维 + dp + Dilworth定理
传送门 文章目录 题意: 思路: 题意: 让你给一个串染色,不同颜色且相邻的一对字符可以互换位置,用最少的颜色,使交换后这个字符串字典序最小. 思路: 考虑将字符串分成若干个非递减的子序列,由于其非递 ...
- HDU 5836 Rubik's Cube BFS
Rubik's Cube 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5836 Description As we all know, Zhu is ...
- C1. Pokémon Army (easy version)(DP)
C1. Pokémon Army (easy version)(DP) 思路:dpdpdp. 考虑:分数组长度的奇偶性进行dpdpdp. 令dp[i][0]dp[i][0]dp[i][0]表示前iii ...
- 算法设计与分析: 5-22 魔方(Rubik's Cube)问题
5-22 魔方(Rubik's Cube)问题 问题描述 3×3×33×3×33\times3\times3 魔方的构造如图所示.图中英文字母 U,L,F,R,B,D 分别表示魔方的 6 个面中的上面 ...
- 【CF 149D】Coloring Brackets(dp)
[CF 149D]Coloring Brackets(dp) D. Coloring Brackets time limit per test 2 seconds memory limit per t ...
- E2. Square-free division (hard version) dp + 质因子分解
传送门 文章目录 题意: 思路: 题意: 给你长度为nnn的数组,让后最多修改其中kkk个数(可以修改为任意数),让后问你分成的最少组是多少.这个组内元素是连续的且不存在任意两个数的积为平方数. 思路 ...
- CodeForces - 1497E2 Square-free division (hard version)(dp+数论)
题目链接:点击查看 题目大意:给出一个长度为 nnn 的数列,现在最多可以修改 kkk 个数字为任意数值,现在问最少可以将数列划分成多少个连续的数列,使得每一个单独的段中,任意两个数的乘积都不能是完全 ...
- Codeforces Round #579 (Div. 3) F2. Complete the Projects (hard version) dp + 贪心
传送门 文章目录 题意: 思路: 题意: 思路: 排序方式跟easyeasyeasy版本的一样,但是hardhardhard版本是输出最多能选多少,所以我们对b<0b<0b<0的情况 ...
最新文章
- CV00-04-卷积
- 堆栈的应用——用JavaScript描述数据结构
- CMD用什么命令可以删除服务?
- BAT脚本如何自动执行 adb shell 以后的命令
- 阿里代码扫描插件安装 (IDEA)
- [转载自简书] ASPNetCore上传大文件碰到的一些问题总结
- Silverlight控件-Slider
- 从零开始数据科学与机器学习算法-人工神经网络与反向传播-09
- php odbc驱动,用于Windows的PHP 7.0 ODBC驱动程序
- java代码安全检测机制_全面解析:java中的反射机制,内含代码验证解析
- .net java 开源_为什么说微软开源 .net 也拼不过 java?
- 平面设计师进步素材模板,设计基础!
- php下标排序,php二维数组指定下标排序
- 图像变形功能的应用: 在线修整发型
- Oracle中 如何用一个表的数据更新另一个表中的数据(含表备份)
- 手把手系列--华邦W25Q64JV Flash操作指南
- Postman测试导出导入Excel教程
- 信息系统安全思维导图
- 《Spring Cloud Netflix》--服务注册和服务发现-Eureka的深入了解
- matlab solve和subs,【MATLAB】matlab中的subs()函数和solve()函数用法
热门文章
- 【PP主数据】工作中心介绍
- 如何做好OA流程审批?
- ABAP Subscreen and tabstrip controls
- SAP成本收集器两则
- python非阻塞输入_python_非阻塞套接字及I/O流
- python竞赛_浅谈Python在信息学竞赛中的运用及Python的基本用法
- java struts2 excel上传_文件上传下载——通过struts的FormFile上传单个excel文件
- web.config mysql_web.config配置mysql数据库连接
- 指针不显示 upupw_Go高级编程:指针和内存分配详解
- ctf(pwn) canary保护机制讲解 与 解密方法介绍