题目大意

有一个 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. Thymeleaf+Spring使用自己的工具类

    第一种.提供思路,继承SpringStandardDialect,重写getExpressionObjectFactory方法,设置expressionObjectFactory的实际对象,并在Tem ...

  2. AQS 支持两种同步方式?

    1.独占式 2.共享式 这样方便使用者实现不同类型的同步组件,独占式如 ReentrantLock,共享式如 Semaphore,CountDownLatch,组合式的如 ReentrantReadW ...

  3. centos 7环境下安装部署zookeeper

    近一直在看zookeeper的知识,有所收获,打算写些一些关于zookeeper的博客,也当做是自己的复习和笔记. 在上一篇 博客中简单地介绍了centos 7 下如何安装jdk,这一篇将介绍如何在c ...

  4. 机器学习之近邻算法模型(KNN)

    1..导引 如何进行电影分类 众所周知,电影可以按照题材分类,然而题材本身是如何定义的?由谁来判定某部电影属于哪 个题材?也就是说同一题材的电影具有哪些公共特征?这些都是在进行电影分类时必须要考虑的问 ...

  5. Altium Designer 设置多层方法及各层介绍

    因为PCB板子的层分类有很多,所以通过帮助大家能更好地理解PCB的结构,所以把我所知道的跟大家分享一下 1.PCB各层简介 1. Top Layer顶层布线层(顶层的走线) 2. Bottom Lay ...

  6. 顺利通过EMC实验(13)

  7. html简单响应式滚动条置顶

    简单响应式滚动条置顶 一般的,让页面出现滚动条的常见方法有: overflow:auto||overflow:scroll 或者overflow-x水平滚动条和overflow-y垂直滚动条 那么现在 ...

  8. 人机交互大作业--flash嵌入web(纯界面)

    界面: 源代码:最近较忙,后续会上传至github

  9. 用SimpleDateFormat求出哪天是星期几,如2008-11-11

    题目5: 巧妙利用SimpleDateFormat求出: 2008-11-11是星期几?import java.text.ParseException;import java.text.SimpleD ...

  10. js select 删除某一项下拉列表的值

    <script type="text/javascript"> //muqingwei modify 通过群组类别选择需要的的群组 var mySelect = doc ...