顾名又思义,是在字符串上进行的DP操作。因为字符串本身可以看作是一个序列,所以有些时候字符串DP可以用区间DP来解决。

P2246 SAC#1 - Hello World(升级版)

题目描述

在讲义的某一面,他看见了一篇文章。这篇文章由英文字母(大小写均有)、数字、和空白字符(制表/空格/回车)构成。

pipapi想起了他最近刚刚学会写的Hello World程序。他非常好奇,这篇文章中,“HelloWorld”作为子序列到底出现过多少次呢?

由于papapi是个智障,大小写对于他而言毫无区别;因此,“hEllOWorLD”这样的子序列也是可以接受的。O和W之间的空格是也是可以少的;也就是说,“HelloWorld”是可以的。根据标程的意思,就是没有空格,不用考虑空格的情况。

两个子序列相同当且仅当它们每一个字符所在的位置都相同。

由于答案可能很大,请输出结果对1000000007(10^9+7)的余数。

输入输出格式

输入格式:

输入包含若干行。这些行的内容共同构成一篇文章。

文章以EOF(文件结尾)结束。

输出格式:

输出仅包含一个整数,表示这篇文章中“Hello World”出现的次数。 d

输入输出样例

输入样例#1:

HhEeLlLlOoWwOoRrLlDd

输出样例#1:

1536

输入样例#2:

Gou Li Guo Jia Sheng Si Yi

Qi Yin Huo Fu Bi Qu Zhi

River can feed people

Also can race boats

Hall Ellen Ok Words locked

输出样例#2:

273

说明

记n为输入的文章的长度(字符数)。

对于20%的数据,n <= 20。

对于50%的数据,n <= 500。

对于所有的数据,15 <= n <= 500000。

入门题。设\(dp[i][j]\)表示文本串前i个字符匹配helloworld模板的前j个字符的匹配数。显然当\(a[i]=b[j]\)时有\(dp[i][j]=dp[i-1][j-1] + dp[i-1][j]\),其他情况\(dp[i][j]=dp[i-1][j]\)。前面一维直接滚动优化掉。

#include

#include

#include

#include

#include

using namespace std;

typedef long long LL;

const int MOD = 1e9 + 7;

char ch1[233] = "#helloworld";

char ch2[233] = "#HELLOWORLD";

int f[233];

int main() {

char x; f[0] = 1;

while ((x = getchar())!=EOF)

for (int i = 10; i >= 1; -- i)

if (x == ch1[i] || x == ch2[i])

f[i] = (f[i-1] + f[i]) % MOD;

cout << f[10] << endl;

return 0;

}

P2890 [USACO07OPEN]便宜的回文Cheapest Palindrome

题目描述

Keeping track of all the cows can be a tricky task so Farmer John has installed a system to automate it. He has installed on each cow an electronic ID tag that the system will read as the cows pass by a scanner. Each ID tag's contents are currently a single string with length M (1 ≤ M ≤ 2,000) characters drawn from an alphabet of N (1 ≤ N ≤ 26) different symbols (namely, the lower-case roman alphabet).

Cows, being the mischievous creatures they are, sometimes try to spoof the system by walking backwards. While a cow whose ID is "abcba" would read the same no matter which direction the she walks, a cow with the ID "abcb" can potentially register as two different IDs ("abcb" and "bcba").

FJ would like to change the cows's ID tags so they read the same no matter which direction the cow walks by. For example, "abcb" can be changed by adding "a" at the end to form "abcba" so that the ID is palindromic (reads the same forwards and backwards). Some other ways to change the ID to be palindromic are include adding the three letters "bcb" to the begining to yield the ID "bcbabcb" or removing the letter "a" to yield the ID "bcb". One can add or remove characters at any location in the string yielding a string longer or shorter than the original string.

Unfortunately as the ID tags are electronic, each character insertion or deletion has a cost (0 ≤ cost ≤ 10,000) which varies depending on exactly which character value to be added or deleted. Given the content of a cow's ID tag and the cost of inserting or deleting each of the alphabet's characters, find the minimum cost to change the ID tag so it satisfies FJ's requirements. An empty ID tag is considered to satisfy the requirements of reading the same forward and backward. Only letters with associated costs can be added to a string.

字串S长M,由N个小写字母构成。欲通过增删字母将其变为回文串,增删特定字母花费不同,求最小花费。

输入输出格式

输入格式:

Line 1: Two space-separated integers: N and M

Line 2: This line contains exactly M characters which constitute the initial ID string

Lines 3..N+2: Each line contains three space-separated entities: a character of the input alphabet and two integers which are respectively the cost of adding and deleting that character.

输出格式:

Line 1: A single line with a single integer that is the minimum cost to change the given name tag.

输入输出样例

输入样例#1:

3 4

abcb

a 1000 1100

b 350 700

c 200 800

输出样例#1:

900

说明

If we insert an "a" on the end to get "abcba", the cost would be 1000. If we delete the "a" on the beginning to get "bcb", the cost would be 1100. If we insert "bcb" at the begining of the string, the cost would be 350 + 200 + 350 = 900, which is the minimum.

比较经典的字符串DP了。设\(dp[i][j]\)表示区间[i,j]变成回文串的最小花费,需要用到区间DP的思想。考虑如何用一个小区间更新一个大区间。如果大区间是\(dp[i][j]\),若s[i]=s[j],那么\(dp[i][j]=dp[i+1][j-1]\),即当前大区间可以由去掉其两端的小区间更新而来而不用花费。不等的时候,\(dp[i][j]=min(dp[i+1][j]+min(add[s[i]],del[s[i]]),dp[i][j-1]+min(add[s[j],del[s[j]]])\)

#include

#include

using namespace std;

const int M = 2005, N = 256;

int n, m;

char c, s[M];

int del[N], add[N], f[M][M];

int main() {

scanf("%d%d%s", &n, &m, (s+1));

for (int i = 1; i <= n; ++ i) {

cin >> c;

cin >> add[c] >> del[c];

}

for (int L = 2; L <= m; ++ L)

for (int i = 1; i + L - 1 <= m; ++ i) {

int j = i + L - 1;

if (s[i] == s[j]) f[i][j] = f[i + 1][j - 1];

else f[i][j] = min(f[i+1][j] + min(add[s[i]], del[s[i]]),

f[i][j-1] + min(add[s[j]], del[s[j]]));

}

cout<

return 0;

}

P1279 字串距离

题目描述

设有字符串X,我们称在X的头尾及中间插入任意多个空格后构成的新字符串为X的扩展串,如字符串X为”abcbcd”,则字符串“abcb□cd”,“□a□bcbcd□”和“abcb□cd□”都是X的扩展串,这里“□”代表空格字符。

如果A1是字符串A的扩展串,B1是字符串B的扩展串,A1与B1具有相同的长度,那么我扪定义字符串A1与B1的距离为相应位置上的字符的距离总和,而两个非空格字符的距离定义为它们的ASCII码的差的绝对值,而空格字符与其他任意字符之间的距离为已知的定值K,空格字符与空格字符的距离为0。在字符串A、B的所有扩展串中,必定存在两个等长的扩展串A1、B1,使得A1与B1之间的距离达到最小,我们将这一距离定义为字符串A、B的距离。

请你写一个程序,求出字符串A、B的距离。

输入输出格式

输入格式:

输入文件第一行为字符串A,第二行为字符串B。A、B均由小写字母组成且长度均不超过2000。第三行为一个整数K(1≤K≤100),表示空格与其他字符的距离。

输出格式:

输出文件仅一行包含一个整数,表示所求得字符串A、B的距离。

输入输出样例

输入样例#1

cmc

snmn

2

输出样例#1:

10

\(dp[i][j]\)表示第一个串的前i个字符和第二个串的前j个字符的最优值,两个空格对应显然没有意义,那么有3种转移:\(dp[i-1][j]+K\),\(dp[i][j-1]+K\),\(dp[i-1][j-1]+abs(S1[i]-S2[j])\),分别表示S1[i]与空格匹配,S2[j]与空格匹配,S1[i]与S2[j]匹配。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;

const int MAXN = 2010;

int K;

char S1[MAXN], S2[MAXN];

int dp[MAXN][MAXN];

int clac(int i, int j) {

return abs((int) (S1[i] - 'a') - (int) (S2[j] - 'a'));

}

int main( ) {

scanf("%s%s%d", S1 + 1, S2 + 1, &K);

int len1 = strlen(S1 + 1), len2 = strlen(S2 + 1);

memset(dp, 63, sizeof(dp));

dp[0][0] = 0;

for (int i = 0; i <= len1; ++ i)

for (int j = 0; j <= len2; ++ j) {

if (i) dp[i][j] = min(dp[i][j], dp[i - 1][j] + K);

if (j) dp[i][j] = min(dp[i][j], dp[i][j - 1] + K);

if (i && j)

dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + clac(i, j));

}

printf("%d\n", dp[len1][len2]);

return 0;

}

caioj 1061: [视频]背包7(匹配性填满型 完全 背包)

时间限制: 1 Sec 内存限制: 128 MB

【问题描述】

判断句子是否可以被划分成若干单词,这些单词只可以 “one”、“puton”、“out”、“output”、“in”和“input”。

输入n个字符串,长度不超过1000000,表示一句句子。

如果可能是那两个人的对话,则输出“YES”;否则,输出“NO”。

【输入文件】

第一行一个整数n,表示一共有n句句子。

此后每行一个字符串,表示一句句子。

【输出文件】

n行,每行一个“YES”或“NO”,表示你的判断结果。

样例输入输出

样例输入

6

puton

inonputin

oneputonininputoutoutput

oneininputwooutoutput

outpu

utput

样例输出

YES

NO

YES

NO

NO

NO

如果不知道这是一道背包题的话,可能没几个人会往背包的方面想。我们不妨把题目中给定的6个单词看做六个数量无限的物品,现在他们要装到一个背包中,比如要装一个input,能装入背包的条件是当前装了一些的背包中,再往后需要的字母依次是i,n,p,u,t。最后成功的条件是背包被装满,即\(dp[串长]\)有值。\(dp[i]\)表示前i个字符是否能完成匹配。如上所述,则dp[i]能由dp[i - len[i]] 推出,当且仅当,子串c[j - len[i] ~ j] 为给定的单词。

单纯这样做还会TLE。可以简单优化一下,具体参照代码。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;

const int MAXM = 1000010;

const int MAXN = 1010;

int n;

string c[] = {"", "one", "puton", "out", "output", "in", "input"};

int len[] = {0, 3, 5, 3, 6, 2, 5};

int dp[MAXM];

int main( ) {

scanf("%d", &n);

string s; int l;

for (int i = 1; i <= n; ++ i) {

memset(dp, 0, sizeof(dp));

cin >> s;

l = s.size( );

dp[0] = 1;

for (int j = 1; j <= l; ++ j)

if(s[j - 1] == 'e' || s[j - 1] == 'n' || s[j - 1] == 't') //优化

for (int i = 1; i <= 6; ++ i)

if (j - len[i] >= 0)

if(s[j - len[i]] == 'o' || s[j - len[i]] == 'p' || s[j - len[i]] == 'i') //优化

if (s.substr(j - len[i], len[i]) == c[i])

dp[j] = dp[j] | dp[j - len[i]];

if (dp[l]) printf("YES\n");

else printf("NO\n");

}

}

P1136 迎接仪式

题目描述

LHX教主要来X市指导OI学习工作了。为了迎接教主,在一条道路旁,一群Orz教主er穿着文化衫站在道路两旁迎接教主,每件文化衫上都印着大字。一旁的Orzer依次摆出“欢迎欢迎欢迎欢迎……”的大字,但是领队突然发现,另一旁穿着“教”和“主”字文化衫的Orzer却不太和谐。

为了简单描述这个不和谐的队列,我们用“j”替代“教”,“z”替代“主”。而一个“j”与“z”组成的序列则可以描述当前的队列。为了让教主看得尽量舒服,你必须调整队列,使得“jz”子串尽量多。每次调整你可以交换任意位置上的两个人,也就是序列中任意位置上的两个字母。而因为教主马上就来了,时间仅够最多作K次调整(当然可以调整不满K次),所以这个问题交给了你。

输入输出格式

输入格式:

第一行包含2个正整数N与K,表示了序列长度与最多交换次数。

第二行包含了一个长度为N的字符串,字符串仅由字母“j”与字母“z”组成,描述了这个序列。

输出格式:

一个非负整数,为调整最多K次后最后最多能出现多少个“jz”子串。

输入输出样例

输入样例#1:

5 2

zzzjj

输出样例#1:

2

说明

【样例说明】

第1次交换位置1上的z和位置4上的j,变为jzzzj;

第2次交换位置4上的z和位置5上的j,变为jzzjz。

最后的串有2个“jz”子串。

【数据规模与约定】

对于10%的数据,有N≤10;

对于30%的数据,有K≤10;

对于40%的数据,有N≤50;

对于100%的数据,有N≤500,K≤100。

一开始不知道怎么做。考虑\(dp[i][j][k]\)表示考虑前i个字符,有j个j变成了z,k个z变成了j。

然后呢?

然后我就不知道了

首先显然两个一样的字符不会被修改。

相邻两字符有四种情况可以转移:zj jz jj zz。

若\(s[i]='j' ~\&\&~ s[i-1]='z'\),\(dp[i][j][k]=max(dp[i][j][k],dp[i-2][j][k]+1);\)

若\(s[i]='z' ~\&\&~ s[i-1]='j'\),\(dp[i][j][k]=max(dp[i][j][k],dp[i-2][j-1][k-1]+1);\)

上面两种情况都比较显然。

那么另外两种情况呢?

若\(s[i]='j' ~\&\&~ s[i-1]='j'\),\(dp[i][j][k]=max(dp[i][j][k],dp[i-2][j-1][k]+1);\)

若\(s[i]='z' ~\&\&~ s[i-1]='z'\),\(dp[i][j][k]=max(dp[i][j][k],dp[i-2][j][k-1]+1);\)

感性理解一下就是,我把不合法的变成合法的,可以看做当前不合法的与前面或后面某个数交换了一下,使之合法,但具体是与哪个数交换的,我们不需要去知道。因为当交换次数\(j=k\)时,显然是存在至少一种合法的操作顺序,令原字符串可以通过j=k次交换变成合法。当交换次数\(j \not= k\)时,显然不存在这种交换方式,那我们就不必去管他。

最后对所有的\(dp[N][i][i]\)取max。

比较巧妙。

顺便,注意边界处理。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;

const int INF = 0x3f3f3f3f;

const int MAXN = 510;

const int MAXK = 110;

int N, K;

//dp[i][j][k]表示考虑前i个字符,有j个‘j’变成了z,k个‘z’变成了j

int l[MAXN], dp[MAXN][MAXK][MAXK];

char tmp[MAXN];

template

inline void read(_Tp &x) {

char ch = getchar( ); bool f = 0; x = 0;

while (!isdigit(ch)) { if (ch == '-') f = 1; ch = getchar( ); }

while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar( );

x = f ? -x : x;

}

int main( ) {

memset(dp, ~63, sizeof(dp));

read(N), read(K);

scanf("%s", tmp + 1);

for (int i = 1; i <= N; ++ i)

if (tmp[i] == 'z') l[i] = 1;

else l[i] = 0;

//for (int i = 1; i <= N; ++ i) printf("%d\n", l[i]);

dp[0][0][0] = dp[1][0][0] = dp[1][l[1]][l[1]] = 0;

for (int i = 2; i <= N; ++ i)

for (int j = 0; j <= K; ++ j)

for (int k = 0; k <= K; ++ k) {

dp[i][j][k] = dp[i - 1][j][k];

if (!l[i - 1] && l[i])

dp[i][j][k] = max(dp[i][j][k], dp[i - 2][j][k] + 1);

if (k && l[i] && l[i - 1])

dp[i][j][k] = max(dp[i][j][k], dp[i - 2][j][k - 1] + 1);

if (j && !l[i] && !l[i - 1])

dp[i][j][k] = max(dp[i][j][k], dp[i - 2][j - 1][k] + 1);

if (j && k && !l[i] && l[i - 1])

dp[i][j][k] = max(dp[i][j][k], dp[i - 2][j - 1][k - 1] + 1);

}

int ans = 0;

for (int i = 0; i <= K; ++ i) ans = max(ans, dp[N][i][i]);

printf("%d\n", ans);

return 0;

}

java字符串匹配dp_[OI]字符串DP小结相关推荐

  1. [OI]字符串DP小结

    顾名又思义,是在字符串上进行的DP操作.因为字符串本身可以看作是一个序列,所以有些时候字符串DP可以用区间DP来解决. P2246 SAC#1 - Hello World(升级版) 题目描述 在讲义的 ...

  2. java 字符串匹配_多模字符串匹配算法原理及Java实现代码

    多模字符串匹配算法在这里指的是在一个字符串中寻找多个模式字符字串的问题.一般来说,给出一个长字符串和很多短模式字符串,如何最快最省的求出哪些模式字符串出现在长字符串中是我们所要思考的.该算法广泛应用于 ...

  3. iOS 字符串截取、iOS 字符串替换、iOS 字符串分隔、iOS 字符串匹配、截取字符串、匹配字符串、分隔字符串

    iOS之字符串截取.iOS 字符串替换.iOS字符串分隔.iOS之字符串匹配.截取字符串.匹配字符串.分隔字符串 1.iOS 字符串截取 //1.ios截取字符串NSString *string =@ ...

  4. 蓝桥杯 java 字符串匹配

    问题描述 给出一个字符串和多行文字,在这些文字中找到字符串出现的那些行.你的程序还需支持大小写敏感选项:当选项打开时,表示同一个字母的大写和小写看作不同的字符:当选项关闭时,表示同一个字母的大写和小写 ...

  5. java字符串匹配dp_Java数据结构与算法之交错字符串97(DP)

    给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的. 思路分析 当我看到这道题的第一想法是用三指针的方法解决:index1指向s1,index2指向s2,inde ...

  6. java匹配字符串替换_Java 字符串匹配和替换字符串

    在java里,在字符串中找字符很方便. 如下例子: String fileContent="this is a  flash call html this flash file=sdcard ...

  7. java字符后移_java把字符串参数往后移3位后输出

    //我想把字符串参数往后移3位后输出packagepassword;importjava.io.IOException;classjiami{Strings1;Stringjiami(Strings) ...

  8. java字符串匹配_Java实现字符串匹配(基于正则)

    有一个String,如何查询其中是否有y和f字符?最黑暗的办法就是: 程序1:我知道if.for语句和charAt() class Test{ public static void main(Stri ...

  9. java字符数组转化为字符串_java字符数组转字符串,java数组转字符串

    字符串转数组 使用Java split() 方法 split() 方法根据匹配给定的正则表达式来拆分字符串. 注意: . . | 和 * 等转义字符,必须得加 \\.多个分隔符,可以用 | 作为连字符 ...

最新文章

  1. lintcode:打劫房屋 III
  2. struct2 开发环境搭建 问题
  3. 如何接受上级指令_向上级领导汇报工作是经常的,想得赏识,了解如何接受上级的命令...
  4. 求最长回文串-从动态规划到马拉车之路(下)
  5. 一般通话记录能保存多少条_打新债中签率一般为多少 中一次新债能赚多少
  6. 【linux系统编程】理解冯•诺依曼体系结构
  7. Forrester报告拆解:强劲冲击第一梯队后,京东智联云站稳云市场新格局
  8. ftp ---- 认识ftp
  9. 消格子时一个很深的bug的修复纪录
  10. 这月到手的工资多了没?
  11. mysql数据库优化方向
  12. ib网卡命令_linux安装卸载IB网卡(mellanox)驱动
  13. 微信怎样知道经常聊天的人
  14. [乐意黎原创] 2018年度CSDN博客排名前一百五十强
  15. 什么第一台多媒体电子计算机诞生,第一台多媒体电计算机是哪一年诞生的
  16. 能锦上添花不能雪中送炭,公关救不了货车帮和作业帮
  17. BBS(仿博客园系统)项目03(主页搭建、个人站点搭建(侧边栏分类展示、标签展示、日期归档)、文章详情页相关功能实现)...
  18. 30岁转行做程序员是一种怎样的体验?
  19. java关于hashmap编程题_在Java中,关于HashMap类的描述,以下说法错误的是( )。...
  20. 深入理解C++的动态绑定和静态绑定 1

热门文章

  1. golang获取程序运行路径
  2. ASP.NET MVC 3发布报错(ASP.NET MVC 3在没有安装环境的服务器上运行)的解决方案
  3. 在android中ScrollView嵌套ScrollView解决方案
  4. QT5获取CPU编号和硬盘序列号
  5. PyTorch系列 (二): pytorch数据读取自制数据集并
  6. c++ for each 遍历tuple
  7. Bootstrap 幻灯片效果
  8. iphone6s发布会_iPhone 6S/SE升级iOS 13性能测试:App启动速度比iOS 12.4.1慢
  9. 将dll制作成控件_全国首例将“影视作品”制作成“网络图片集”方式侵权案宣判...
  10. datatable怎么根据两列分组_公司要IT转型,我该怎么办?用Python进行数据处理