题目大意

有一个 01 串集合 \(S\),其中每个串的长度都不超过 \(N\),你要求出 \(S\) 中至少是 \(K\) 个串的子序列的最长串,如果有多解,输出字典序最小的那组解。

由于 \(S\) 可能很大,因此我们是这样描述 \(S\) 的:

  • 你将得到 \((N+1)\) 个 01 串,第 \(i\) 个串的长度为 \(2^{i-1}\)。
  • 第 \(i\) 个字符串的第 \(j\) 个字符,代表数字 \((j−1)\) 的、长度为 \((i−1)\) 的二进制表示是否出现在 \(S\) 中。

\(N \leq 20\)。

解题思路

讲题的时候一直讲子序列自动机搞得我以为解法是 YY 一个广义子序列自动机什么的,嘤。

其实是用贪心的思想去匹配,然后记录每种匹配过程的可能性,再压状态。

用 \(f(S_1, S_2)\) 表示已经匹配的子序列是 \(S_1\),还可匹配的串是 \(S_2\) 的情况数。

显然初始是 \(f(\empty,T) = 1\),而每个字符串的答案是 \(f(S,\empty)\)。转移就枚举下一个匹配 \(0/1\) 就好了。

需要注意的是状态要压一压。

考虑记录成 \(f(len,S_1|S_2)\) 即因为 \(|S_1|+|S_2|\le N\),所以把两者存在一起,空间复杂度才对。

只有 \(len\) 是找不到分割点的,不知道 \(0\) 到底是空,还是匹配了一位 \(0\),不过每个串前面补个 \(1\) 就好了。

不仅是题解代码的两倍长,空间复杂度还很高 QAQ

#include <set>
#include <map>
#include <queue>
#include <bitset>
#include <vector>
#include <math.h>
#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
/*
添加 1 应该完全不影响才是()
除了 f 数组的第一维,所有的长度都一定是字符串的实际长度,包括添加的 1 ;
S 和 S1 一定是 1 开头,但是 S2 不一定;
原字符串最长为 n,有 (1 << n + 1) - 1 种
新字符串最长为 n + 1,有 (1 << n + 2) - 1 种
*/
const int N(20); int n, k;
int f[2][1 << N + 1], g[N + 1][1 << N + 1];
int s[1 << N + 1], len[1 << N + 1];
char ch[1 << N];
struct pal{ int l, S; } nx[N + 2][1 << N + 1][2]; inline void read(int &x){
x = 0; int f = 1, c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)) x = x * 10 + c - 48, c = getchar();
x *= f;
} inline void out(int len, int S){
if(len < 0) return; if(len == 0){ cerr << "empty\n"; return; }
for(int i(len - 1); ~i; --i) printf("%d", !!(S & (1 << i)));
puts("");
} void input(){
read(n), read(k);
for(int i(0); i <= n; ++i){
scanf("%s", ch); int m = strlen(ch);
for(int j(0); j < m; ++j)
len[j | (1 << i)] = i + 1, s[j | (1 << i)] = ch[j] - '0';
}
} void init(){
for(int i(1); i < 1 << n + 1; ++i) if(s[i]) f[0][i] = 1;
nx[0][0][0] = nx[0][0][1] = {-1};
for(int i(1); i <= n + 1; ++i)
for(int j(0); j < 1 << i; ++j){
int p = j >> (i - 1), S = j & (1 << i - 1) - 1;
nx[i][j][p] = {i - 1, S};
nx[i][j][p ^ 1] = nx[i - 1][S][p ^ 1];
}
} void match(){
for(int i(0); i <= n; ++i){
int p = i & 1; memset(f[!p], 0, sizeof f[p]);
for(int j(1); j < 1 << n + 1; ++j){
int S = j; if(!f[p][S]) continue; pal nw;
int S1, S2, l, l1, l2; l = len[S], l1 = i + 1, l2 = l - l1;
S1 = S >> l2, S2 = S & (1 << l2) - 1;
nw = nx[l2][S2][0];
if(nw.l != -1) f[!p][((S1 << 1) << nw.l) | nw.S] += f[p][S];
nw = nx[l2][S2][1];
if(nw.l != -1) f[!p][((S1 << 1 | 1) << nw.l) | nw.S] += f[p][S];
g[i][S1] += f[p][S];
}
}
} void output(){
for(int i(n); ~i; --i)
for(int j(0); j < 1 << i; ++j)
if(g[i][j | (1 << i)] >= k) return out(i, j);
} int main(){
input();
init();
match();
output();
return 0;
}
/* Hemerocallis */

[题解] [AGC024F] Simple Subsequence Problem的更多相关文章

  1. @atcoder - AGC024F@ Simple Subsequence Problem

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定由若干长度 <= N 的 01 字符串组成的集合 S. ...

  2. hdu4976 A simple greedy problem. (贪心+DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=4976 2014 Multi-University Training Contest 10 1006 A simp ...

  3. HDU1757 A Simple Math Problem 矩阵快速幂

    A Simple Math Problem Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  4. SPOJ LIS2 Another Longest Increasing Subsequence Problem 三维偏序最长链 CDQ分治

    Another Longest Increasing Subsequence Problem Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://a ...

  5. FZYZ-2071 A Simple Math Problem IX

    P2071 -- A Simple Math Problem IX 时间限制:1000MS      内存限制:262144KB 状态:Accepted      标签:    数学问题-博弈论    ...

  6. HDU 1757 A Simple Math Problem(矩阵)

    A Simple Math Problem [题目链接]A Simple Math Problem [题目类型]矩阵快速幂 &题解: 这是一个模板题,也算是入门了吧. 推荐一个博客:点这里 跟 ...

  7. 【BZOJ3489】A simple rmq problem(KD-Tree)

    [BZOJ3489]A simple rmq problem(KD-Tree) 题面 BZOJ 题解 直接做肯定不好做,首先我们知道我们是一个二维平面数点,但是限制区间只能出现一次很不好办,那么我们给 ...

  8. 【BZOJ3489】A simple rmq problem

    [BZOJ3489]A simple rmq problem 题面 bzoj 题解 这个题不强制在线的话随便做啊... 考虑强制在线时怎么搞 预处理出一个位置上一个出现的相同数的位置\(pre\)与下 ...

  9. BZOJ3489 A simple rmq problem 【可持久化树套树】*

    BZOJ3489 A simple rmq problem Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一 ...

随机推荐

  1. NO Oracle database,JUST USE Oracle client。远程导入导出dmp

    序言: 你会发现,exp.exe 和imp.exe均存在于Oracle数据库的安装bin目录下.而很多情况下,我们不想安装庞大的Oracle数据库,但想使用imp和exp等工具命令,在我们本地机对Or ...

  2. Python包装器

    def func(): print("func body") def f1(arg): print("f1:",arg) def wrapper(b): pri ...

  3. kafka 的高可用机制是什么?

    这个问题比较系统,回答出 kafka 的系统特点,leader 和 follower 的关系,消息 读写的顺序即可.

  4. Azure DevOps (八) 通过流水线编译Docker镜像

    上一篇文章我们完成了最简单的传统部署:上传应用到服务器上使用守护进程进行应用的部署. 本篇文章我们开始研究容器化和流水线的协作. 在开始操作之前,我们首先需要准备一下我们的dockerfile,这里我 ...

  5. Pandas怎样新增数据列

    Pandas怎样新增数据列? 在进行数据分析时,经常需要按照一定条件创建新的数据列,然后进行进一步分析. 直接赋值 df.apply方法 df.assign方法 按条件选择分组分别赋值 0.读取csv ...

  6. Qunee for HTML5 v1.6新版本发布

    Qunee for HTML5 V1.6正式发布,修复了一些 BUG,增加了滚动条支持,改进了编辑器,增加了JSON 导入导出.告警冒泡.连线流动,UI 定制等扩展示例,欢迎 访问 导航面板 增加了滚 ...

  7. 用原生js写一个"多动症"的简历

    用原生js写一个"多动症"的简历 预览地址源码地址 最近在知乎上看到@方应杭用vue写了一个会动的简历,觉得挺好玩的,研究一下其实现思路,决定试试用原生js来实现. 会动的简历实现 ...

  8. python-使用函数求特殊a串数列和

    给定两个均不超过9的正整数a和n,要求编写函数fn(a,n) 求a+aa+aaa++⋯+aa⋯aa(n个a)之和,fn须返回的是数列和 函数接口定义: 1 fn(a,n) 2 其中 a 和 n 都是用 ...

  9. java中接口和抽象类有什么区别,举例!

    2)接口和抽象类有什么区别?答:马克-to-win:抽象类里可以有实现的方法,接口里不能有,所以相对来讲各方面实现都简单(尤其动态方法调度).另外:类可以实现多个接口.反过来说,也正是抽象类一个致命伤 ...

  10. 字符串反转&说反话

    题目描述 写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串.(字符串长度不超过1000) 输入描述: 输入N个字符 输出描述: 输出该字符串反转后的字符串 示例1 输入 abcd 输出 d ...