Codechef STREDUC Reduce string Trie、bitset、区间DP
简化题意:给出一个长度为\(l\)的模板串\(s\)与若干匹配串\(p_i\),每一次你可以选择\(s\)中的一个出现在集合\(\{p_i\}\)中的子串将其消去,其左右分成的两个串拼接在一起形成新的串\(s\)。问如是进行消除,最后\(s\)的最短长度。
当时没想到做法,现在看起来还是比较简单欸……
考虑计算出所有可以被消除的区间然后\(DP\)
先将所有匹配串插入到Trie树上,设\(f_{i,j,k}\)表示子串\(s_{i,j}\)通过任意消除得到的串是否能对应到\(Trie\)树的\(k\)号节点上。转移分两种:
①在子串\(s_{i,j-1}\)之后接上\(s_j\),直接在\(Trie\)树上找是否存在对应的儿子;②存在某个子串\(s_{x,j}(x > i)\)可以被消除,那么\(\forall k, f_{i,j,k} |= f_{i,x-1,k}\)
计算完成后,如果存在\(k\)使得某一个匹配串在\(Trie\)树上对应节点\(k\)且\(f_{i,j,k}=1\),那么意味着子串\(s_{i,j}\)可以通过消除消除成一个匹配串,那么我们认为子串\(s_{i,j}\)可以被消除,且令\(f_{i,j,root}=1\)表示可以消除为空串。
发现复杂度为\(O(l^3\sum|p_i|)\),但是转移②可以使用bitset进行优化,复杂度就会降为\(O(\frac{l^3 \sum |p_i|}{32})\),而且状态不满,就能很快的跑过了。
计算出可以被消除的区间然后区间DP算出答案。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c) && c != EOF){
if(c == '-')
f = 1;
c = getchar();
}
if(c == EOF)
exit(0);
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return f ? -a : a;
}
struct node{
int ch[26];
}Trie[610];
int dp[251] , cntN = 1 , N , S;
bool can[251][251];
bitset < 610 > f[251][251];
char s[251] , mod[31];
vector < int > End;
void insert(){
int L = strlen(mod + 1) , cur = 1;
for(int i = 1 ; i <= L ; ++i){
if(!Trie[cur].ch[mod[i] - 'a'])
Trie[cur].ch[mod[i] - 'a'] = ++cntN;
cur = Trie[cur].ch[mod[i] - 'a'];
}
End.push_back(cur);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
scanf("%s" , s + 1);
N = strlen(s + 1);
for(int i = 1 ; i <= N ; ++i)
f[i][i - 1][1] = 1;
S = read();
for(int i = 1 ; i <= S ; ++i){
scanf("%s" , mod + 1);
insert();
}
for(int i = 1 ; i <= N ; ++i)
for(int j = i ; j ; --j){
for(int k = 1 ; k <= cntN ; ++k)
if(f[j][i - 1][k] && Trie[k].ch[s[i] - 'a'])
f[j][i][Trie[k].ch[s[i] - 'a']] = 1;
for(int k = j + 1 ; k <= i ; ++k)
if(can[k][i])
f[j][i] |= f[j][k - 1];
for(int k = 0 ; k < S ; ++k)
if(f[j][i][End[k]])
f[j][i][1] = 1;
can[j][i] = f[j][i][1];
}
for(int i = 1 ; i <= N ; ++i){
dp[i] = dp[i - 1] + 1;
for(int j = i ; j >= 0 ; --j)
if(can[j][i])
dp[i] = min(dp[i] , dp[j - 1]);
}
cout << dp[N];
return 0;
}
Codechef STREDUC Reduce string Trie、bitset、区间DP的更多相关文章
- HDU 4570---Multi-bit Trie(区间DP)
题目链接 Problem Description IP lookup is one of the key functions of routers for packets forwarding and ...
- HDU 2476 String painter(区间DP)
String painter Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- String painter (区间dp)
There are two strings A and B with equal length. Both strings are made up of lower case letters. Now ...
- HDU 2476 String painter (区间DP)
题意:给出两个串a和b,一次只能将一个区间刷一次,问最少几次能让a=b 思路:首先考虑最坏的情况,就是先将一个空白字符串刷成b需要的次数,直接区间DP[i][j]表示i到j的最小次数. 再考虑把a变成 ...
- UVA Live Archive 4394 String painter(区间dp)
区间dp,两个str一起考虑很难转移. 看了别人题解以后才知道是做两次dp. dp1.str1最坏情况下和str2完全不相同,相当于从空白串开始刷. 对于一个区间,有两种刷法,一起刷,或者分开来刷. ...
- String painter(区间DP)
There are two strings A and B with equal length. Both strings are made up of lower case letters. Now ...
- HDOJ 题目2474 String painter(区间DP)
String painter Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- UVALive 4394 String painter ——(区间DP)
其实这个dp过程有点似懂非懂...代码如下: #include <stdio.h> #include <algorithm> #include <string.h> ...
- HDU4570:Multi-bit Trie(区间DP)
Problem Description IP lookup is one of the key functions of routers for packets forwarding and clas ...
随机推荐
- 【代码笔记】Web-ionic-index创建侧边栏
一,创建侧边栏. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...
- 数据库开源框架GreenDao的使用解析
数据库开源框架GreenDao的使用解析 1,GreenDao概述 1),greenDao是一个当下十分火热的数据库开源框架,或者说是一个帮助Android开发者将数据存到SQLite中的一个开源项目 ...
- linux上用newman+postman进行自动化测试
第一步:导出postman文件 Postman就是根据collection和enviroment这两个json文件来自动化运行的! 所以从Postman中导出collection和enviroment ...
- 12.2、多线程通信:queue
queue: 什么是队列:是一种特殊的结构,类似于列表.不过就像排队一样,队列中的元素一旦取出,那么就会从队列中删除. 线程之间的通信可以使用队列queue来进行 线程如何使用queue.Queue[ ...
- dmesg七种用法
dmesg 命令的使用范例 ‘dmesg’命令设备故障的诊断是非常重要的.在‘dmesg’命令的帮助下进行硬件的连接或断开连接操作时,我们可以看到硬件的检测或者断开连接的信息.‘dmesg’命令在多数 ...
- .net core 导出Excel(epplus 创建excel )
[Route("getopenfrequencyexcel")] [HttpGet] public IActionResult GetOpenFrequencyExcel(int ...
- 禁用selinux
查看selinux状态: [root@VM000000518 upload]# getenforce Enforcing 禁用: [root@VM000000518 upload]# setenfor ...
- 命令行方式安装Pycharm
sudo apt install snapd snapd-xdg-open snap refresh sudo snap install pycharm-professional --classic
- 4、爬虫之mongodb
mongodb 简介 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和非关系数据库之间的产品 ...
- 2个Excel表格核对技巧
技巧1.利用Spreadsheet Camprare一秒钟识别差异数据 如下图所示,我们如何快速比对我们自己做的表格和上司修改后的表格的差异呢?这里首先来介绍一个非常棒的工具:Spreadsheet ...