题目传送门

  传送门

题目大意

  有一个位置数列,给定$n$条线索,每条线索从某一个位置开始,一直向左或者向右走,每遇到一个还没有在线索中出现的数就将它加入线索,问最小的可能的数列长度。

  依次从左到右考虑每一位上填的数。

  用$f_{L, a, R, b, S}$表示正在满足向右走的线索是$L$,前$a$个字符已经满足,正在满足向左走的线索是$R$,前$b$个字符还没有满足,还未被考虑的线索集合是$S$。

  主要有两种转移:

  • 填下一个字符

    • 如果两个线索下一个要填的字符相同,那么直接填
    • 如果不同则还需判断一下是否会使得另一线索不满足条件。
  • 更换线索
    • 向右走的线索是一堆类似于后缀的东西,向左走的线索是一堆类似于前缀的东西
    • 能不能在某个串的某个位置处更换某个串可以预处理出来

  loj上加了一堆常数优化卡到rk 1,估计很快就被超了。

  记得Doggu指着Claris这道题的非记忆化搜索写法给我说以后见着Claris记着%。

Code

  1. /**
  2. * loj
  3. * Problem#6037
  4. * Accepted
  5. * Time: 1224ms
  6. * Memory: 25208k
  7. */
  8. #include <iostream>
  9. #include <cstdlib>
  10. #include <cstdio>
  11. #include <set>
  12. using namespace std;
  13. typedef bool boolean;
  14.  
  15. const int N = ;
  16. const int Lim = << ;
  17.  
  18. #define last_one(__x) (__builtin_ffs(__x) - 1)
  19.  
  20. int n;
  21. int len[N];
  22. int s[N][N];
  23. int exi[N][N];
  24. int can[N][N]; // L: forward, R: backward
  25. int usable[N][N];
  26. int f[N][N][N][N][];
  27.  
  28. inline void init() {
  29. scanf("%d", &n);
  30. set<int> ss;
  31. for (int i = , x; i < n; i++) {
  32. int l = , hash_val = ;
  33. while (~scanf("%d", &x) && x) {
  34. s[i][l++] = x;
  35. hash_val = hash_val * + x;
  36. }
  37. len[i] = l, s[i][l] = ;
  38. if (ss.count(hash_val))
  39. n--, i--;
  40. else
  41. ss.insert(hash_val);
  42. }
  43.  
  44. for (int i = ; i < n; i++)
  45. for (int j = ; j < len[i]; j++)
  46. exi[i][j + ] = exi[i][j] | ( << s[i][j]);
  47. }
  48.  
  49. // start at pos
  50. boolean check(int a, int pos, int b) {
  51. int *pa = s[a] + pos, *pb = s[b];
  52. while (*pa || *pb) {
  53. if (*pa == *pb)
  54. pa++, pb++;
  55. else if (( << *pb) & exi[a][pa - s[a]])
  56. pb++;
  57. else
  58. return false;
  59. }
  60. return true;
  61. }
  62.  
  63. void upd(int& a, int b) {
  64. if (a > b)
  65. a = b;
  66. }
  67.  
  68. // considering s[L][pl], s[R][pr - 1], S remained
  69. int dp(int L, int pl, int R, int pr, int S) {
  70. if (!S && pl == len[L] && !pr)
  71. return ;
  72. int &rt = f[L][pl][R][pr][S];
  73. if (rt)
  74. return rt;
  75. rt = Lim;
  76.  
  77. for (int T = S & can[L][pl], i = last_one(T); T; T -= (T & (-T)), i = last_one(T))
  78. upd(rt, dp(i, , R, pr, S ^ ( << i)));
  79. if (!pr) {
  80. for (int i = ; i < n && (S >> i); i++)
  81. if ((S >> i) & )
  82. // for (int j = 0; j <= len[i]; j++)
  83. // if ((can[i][j] >> R) & 1)
  84. // upd(rt, dp(L, pl, i, j, S ^ (1 << i)));
  85. for (int T = usable[R][i], j = last_one(T); T; T -= (T & (-T)), j = last_one(T))
  86. upd(rt, dp(L, pl, i, j, S ^ ( << i)));
  87. }
  88.  
  89. if (pl < len[L] || pr) {
  90. int vl = s[L][pl], vr = ((pr) ? (s[R][pr - ]) : ());
  91. if (vl == vr)
  92. upd(rt, dp(L, pl + , R, pr - , S) + );
  93. // if (pl < len[L] && _exi[R][pr] & (1 << vl))
  94. if (pl < len[L] && exi[R][pr] & ( << vl))
  95. upd(rt, dp(L, pl + , R, pr, S) + );
  96. if (pr && exi[L][pl] & ( << vr))
  97. upd(rt, dp(L, pl, R, pr - , S) + );
  98. }
  99. // cerr << L << " " << pl << " " << R << " " << pr << " " << S << " " << rt << '\n';
  100. return rt;
  101. }
  102.  
  103. inline void solve() {
  104. // forward
  105. for (int idx = ; idx < n; idx++) {
  106. for (int pos = ; pos <= len[idx]; pos++) {
  107. for (int ano = ; ano < n; ano++) {
  108. if (ano ^ idx)
  109. can[idx][pos] |= check(idx, pos, ano) << ano;
  110. }
  111. // cerr << can[idx][pos] << ' ';
  112. }
  113. }
  114. for (int i = ; i < n; i++) {
  115. for (int j = ; j < n; j++) {
  116. if (i ^ j) {
  117. for (int pos = ; pos <= len[j]; pos++)
  118. if ((can[j][pos] >> i) & )
  119. usable[i][j] |= ( << pos);
  120. }
  121. }
  122. }
  123. len[n] = ;
  124. for (int i = ; i < N; i++) {
  125. exi[n][i] = ; //_exi[n][i] = 2046;
  126. can[n][i] = ;
  127. }
  128. int all = ( << n) - , ans = Lim;
  129. // ans = dp(n, 0, 1, len[1], all ^ 2);
  130. for (int i = ; i < n; i++) {
  131. upd(ans, dp(n, , i, len[i], all ^ ( << i)));
  132. }
  133. if (ans == Lim)
  134. puts("-1");
  135. else
  136. printf("%d\n", ans);
  137. }
  138.  
  139. int main() {
  140. init();
  141. solve();
  142. return ;
  143. }

loj 6037 「雅礼集训 2017 Day4」猜数列 - 动态规划的更多相关文章

  1. LOJ #6037.「雅礼集训 2017 Day4」猜数列 状压dp

    这个题的搜索可以打到48分…… #include <cstdio> #include <cstring> #include <algorithm> ; bool m ...

  2. Loj 6036 「雅礼集训 2017 Day4」编码 - 2-sat

    题目传送门 唯一的传送门 题目大意 给定$n$个串,每个串只包含 ' .问是否可能任意两个不同的串不满足一个是另一个的前缀. 2-sat的是显然的. 枚举每个通配符填0还是1,然后插入Trie树. 对 ...

  3. 2018.10.27 loj#6035. 「雅礼集训 2017 Day4」洗衣服(贪心+堆)

    传送门 显然的贪心题啊...考试没调出来10pts滚了妙的一啊 直接分别用堆贪心出洗完第iii件衣服需要的最少时间和晾完第iii件衣服需要的最少时间. 我们设第一个算出来的数组是aaa,第二个是bbb ...

  4. LOJ#6035. 「雅礼集训 2017 Day4」洗衣服

    传送门 先处理出每一件衣服最早什么时候洗完,堆+贪心即可 然后同样处理出每件衣服最早什么时候烘干 然后倒序相加取最大值 # include <bits/stdc++.h> using na ...

  5. LOJ #6035.「雅礼集训 2017 Day4」洗衣服 贪心

    这道题的贪心好迷啊~我们对于两个过程进行单独贪心,然后再翻转一个,把这两个拼起来.先说一下单独贪心,单独贪心的话就是用一个堆,每次取出最小的,并且把这个最小的加上他单次的,再放进去.这样,我们得到的结 ...

  6. LOJ #6036.「雅礼集训 2017 Day4」编码 Trie树上2-sat

    记得之前做过几道2-sat裸体,以及几道2-sat前缀优化建图,这道题使用了前缀树上前缀树优化建图.我们暴力建图肯定是n^2级别的,那么我们要是想让边数少点,就得使用一些骚操作.我们观察我们的限制条件 ...

  7. [LOJ 6031]「雅礼集训 2017 Day1」字符串

    [LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...

  8. [LOJ 6030]「雅礼集训 2017 Day1」矩阵

    [LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...

  9. [LOJ 6029]「雅礼集训 2017 Day1」市场

    [LOJ 6029] 「雅礼集训 2017 Day1」市场 题意 给定一个长度为 \(n\) 的数列(从 \(0\) 开始标号), 要求执行 \(q\) 次操作, 每次操作为如下四种操作之一: 1 l ...

随机推荐

  1. python中关于turtle库的学习笔记

    一.基础概念 1.画布:画布就是turtle为我们展开用于绘图区域, 我们可以设置它的大小和初始位置.常用的画布方法有两个:screensize()和setup(). (1)turtle.screen ...

  2. Linux_磁盘分布_以及分区

    运用 Xshell  工具链接到你的服务器 1.     Fdisk -l    这是查看磁盘挂载列表情况 2.      Fdisk /dev/vdc   这是分区这个磁盘   m    是查看信息 ...

  3. Java面试题和解答(四)

    1.JVM什么情况下会GC,GC策略有哪些 当应用程序分配新的对象,GC的代的预算大小已经达到阈值,比如GC的第0代已满:代码主动显式调用System.GC.Collect():其他特殊情况,比如,系 ...

  4. 代码块: 以冒号作为开始,用缩进来划分作用域,这个整体叫做代码块,python的代码块可以提升整体的整齐度,提高开发效率

    # ### 代码块: 以冒号作为开始,用缩进来划分作用域,这个整体叫做代码块 if 5 == 5: print(1) print(2) if True: print(3) print(4) if Fa ...

  5. [js]d3.js绘制拓扑树

    echart也支持拓扑树了 所需的json数据格式: children嵌套 vis.js也支持绘制拓扑树 数据格式: nodes: {id, label, title} edges: {from, t ...

  6. 如何优雅的写一个Vue 的弹框

    写Vue或者是react 都会遇见弹框的问题.也尝试了多种办法来写弹框,一直都不太满意,今天特地看了一下 Element UI 的源码,模仿着写了一个简易版. 大概有一下几个问题: 1.弹框的层级问题 ...

  7. Percona-Toolkit 之 pt-table-checksum 总结

    pt-table-checksum - Verify MySQL replication integrity. pt-table-checksum performs an online replica ...

  8. Linux的发展历史

    创始人: linux操作系统由林纳斯·本纳第克特·托瓦兹编写而成,是管理电脑硬件以及运行电脑软件的操作系统. 创始发展过程:Linux操作系统的诞生.发展和成长过程始终依赖着五个重要支柱:UNIX 操 ...

  9. 软件工程first homework

    1) 2017*****7193:我是最乐观的刘新飞:我的爱好是下中国象棋和听音乐: 我的码云个人主页是码云个人主页: 我的第一个项目地址是×××: 自己目前的代码量是三千行左右:我最喜欢蛋肠炒面(一 ...

  10. 扎实学Java之数组与方法

    什么是数组? 数组是一个容器,用来存储多个数据(数据类型相同) 声明一个数组就是在内存中开辟一串连续的空间 数组的结构和基本要素 标识符:数组的名称,用于区分不同的数组 数组元素:向数组中存放的数据 ...