题意 :

  • 其他条件和上题相同
  • 这里已知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)相关推荐

  1. E1. Rubik‘s Cube Coloring (easy version) 贪心,满二叉树(1300)

    题意 : 给定一个层数为k的满二叉树,结点编号为标准的层序遍历的编号 魔方有六个面,如图,每个面一个颜色 树上的结点的颜色也是这六个颜色之一,但是两个相邻结点的颜色必须是 魔方中,颜色相邻的两种颜色 ...

  2. Codeforces Round #617 (Div. 3) E2. String Coloring (hard version) 思维 + dp + Dilworth定理

    传送门 文章目录 题意: 思路: 题意: 让你给一个串染色,不同颜色且相邻的一对字符可以互换位置,用最少的颜色,使交换后这个字符串字典序最小. 思路: 考虑将字符串分成若干个非递减的子序列,由于其非递 ...

  3. 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 ...

  4. 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. 算法设计与分析: 5-22 魔方(Rubik's Cube)问题

    5-22 魔方(Rubik's Cube)问题 问题描述 3×3×33×3×33\times3\times3 魔方的构造如图所示.图中英文字母 U,L,F,R,B,D 分别表示魔方的 6 个面中的上面 ...

  6. 【CF 149D】Coloring Brackets(dp)

    [CF 149D]Coloring Brackets(dp) D. Coloring Brackets time limit per test 2 seconds memory limit per t ...

  7. E2. Square-free division (hard version) dp + 质因子分解

    传送门 文章目录 题意: 思路: 题意: 给你长度为nnn的数组,让后最多修改其中kkk个数(可以修改为任意数),让后问你分成的最少组是多少.这个组内元素是连续的且不存在任意两个数的积为平方数. 思路 ...

  8. CodeForces - 1497E2 Square-free division (hard version)(dp+数论)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的数列,现在最多可以修改 kkk 个数字为任意数值,现在问最少可以将数列划分成多少个连续的数列,使得每一个单独的段中,任意两个数的乘积都不能是完全 ...

  9. Codeforces Round #579 (Div. 3) F2. Complete the Projects (hard version) dp + 贪心

    传送门 文章目录 题意: 思路: 题意: 思路: 排序方式跟easyeasyeasy版本的一样,但是hardhardhard版本是输出最多能选多少,所以我们对b<0b<0b<0的情况 ...

最新文章

  1. CV00-04-卷积
  2. 堆栈的应用——用JavaScript描述数据结构
  3. CMD用什么命令可以删除服务?
  4. BAT脚本如何自动执行 adb shell 以后的命令
  5. 阿里代码扫描插件安装 (IDEA)
  6. [转载自简书] ASPNetCore上传大文件碰到的一些问题总结
  7. Silverlight控件-Slider
  8. 从零开始数据科学与机器学习算法-人工神经网络与反向传播-09
  9. php odbc驱动,用于Windows的PHP 7.0 ODBC驱动程序
  10. java代码安全检测机制_全面解析:java中的反射机制,内含代码验证解析
  11. .net java 开源_为什么说微软开源 .net 也拼不过 java?
  12. 平面设计师进步素材模板,设计基础!
  13. php下标排序,php二维数组指定下标排序
  14. 图像变形功能的应用: 在线修整发型
  15. Oracle中 如何用一个表的数据更新另一个表中的数据(含表备份)
  16. 手把手系列--华邦W25Q64JV Flash操作指南
  17. Postman测试导出导入Excel教程
  18. 信息系统安全思维导图
  19. 《Spring Cloud Netflix》--服务注册和服务发现-Eureka的深入了解
  20. matlab solve和subs,【MATLAB】matlab中的subs()函数和solve()函数用法

热门文章

  1. 【PP主数据】工作中心介绍
  2. 如何做好OA流程审批?
  3. ABAP Subscreen and tabstrip controls
  4. SAP成本收集器两则
  5. python非阻塞输入_python_非阻塞套接字及I/O流
  6. python竞赛_浅谈Python在信息学竞赛中的运用及Python的基本用法
  7. java struts2 excel上传_文件上传下载——通过struts的FormFile上传单个excel文件
  8. web.config mysql_web.config配置mysql数据库连接
  9. 指针不显示 upupw_Go高级编程:指针和内存分配详解
  10. ctf(pwn) canary保护机制讲解 与 解密方法介绍