P1616 疯狂的采药
题目背景
此题为纪念 LiYuxiang 而生。
题目描述
LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是 LiYuxiang,你能完成这个任务吗?
此题和原题的不同点:
11. 每种草药可以无限制地疯狂采摘。
22. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!
输入格式
输入第一行有两个整数,分别代表总共能够用来采药的时间 t 和代表山洞里的草药的数目 m。
第 22 到第 (m+1) 行,每行两个整数,第(i+1) 行的整数 ai,bi 分别表示采摘第 i 种草药的时间和该草药的价值。
输出格式
输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
输入输出样例
输入 #1复制
70 3 71 100 69 1 1 2
输出 #1复制
140
说明/提示
数据规模与约定
- 对于 30%30% 的数据,保证 m≤103 。
- 对于 100%100% 的数据,保证 1≤m≤104,1≤t≤107,且 1≤m×t≤107,1≤ai,bi≤104。
完全背包和01背包的区别是,完全背包的物品可以无限的取,而01背包的物品只能取一次。
那么在做的时候,只需把遍历的顺序更改一下,就可以实习完全背包,01背包是倒序取值,完全背包是正序取值,我们来看看代码。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
long long dp[10000010];
int w[10010];
int v[10010];
int main()
{ int m,t;
cin>>t>>m;
for(int i=0;i<m;i++)
cin>>w[i]>>v[i];
for(int i=0;i<m;i++)
{
for(int j=w[i];j<=t;j++)//正序取值,与01背包不同点
{
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);//状态转移方程,用一维数组实现dp
}
}
cout <<dp[t]<< endl;
return 0;
}
KMP字符串匹配问题
P3375 【模板】KMP
题目描述
给出两个字符串 s1 和 s2,若 s1 的区间 [l,r] 子串与 s2 完全相同,则称s2 在 s1 中出现了,其出现位置为 l。
现在请你求出 s2 在 s1 中所有出现的位置。
定义一个字符串 s 的 border 为 s 的一个非 s 本身的子串 t,满足 t 既是 s 的前缀,又是 s 的后缀。
对于 s2,你还需要求出对于其每个前缀 's′ 的最长 border ′t′ 的长度。
输入格式
第一行为一个字符串,即为 s1。
第二行为一个字符串,即为 s2。
输出格式
首先输出若干行,每行一个整数,按从小到大的顺序输出 s2 在 s1 中出现的位置。
最后一行输出 ∣s2∣ 个整数,第 i 个整数表示 s2 的长度为 i 的前缀的最长 border 长度。
输入输出样例
输入 #1复制
ABABABC ABA
输出 #1复制
1 3 0 0 1
说明/提示
样例 1 解释
。
对于 s2 长度为 33 的前缀 ABA
,字符串 A
既是其后缀也是其前缀,且是最长的,因此最长 border 长度为 11。
数据规模与约定
本题采用多测试点捆绑测试,共有 3 个子任务。
- Subtask 1(30 points):∣s1∣≤15,∣s2∣≤5。
- Subtask 2(40 points):∣s1∣≤104,∣s2∣≤102。
- Subtask 3(30 points):无特殊约定。
对于全部的测试点,保证 1≤∣s1∣,∣s2∣≤106,s1,s2 中均只含大写英文字母。
首先,什么是KMP算法,模式串匹配,就是给定一个需要处理的文本串(理论上应该很长)和一个需要在文本串中搜索的模式串(理论上长度应该远小于文本串),查询在该文本串中,给出的模式串的出现有无、次数、位置等。
我们学KMP之前得了解前缀和后缀,那么什么是前后缀呢?
举个例子: ABACD
前缀有:A,AB,ABA,ABAC,ABACD
后缀有:D,CD,ACD,BACD,ABACD
那么有了前后缀后如何来进行KMP算法呢,我们还要找出它们的最大相等前后缀,什么是最大相等前后缀,举个例子:ABABC
那么我们来看当下标是2(0开头)时,前缀有,A,AB,ABA
后缀有,A,BA,ABA
那么它最大相等前后缀为3(ABA)简单点就是找最大长度且相等的子串。
比如 ABABC 因为文本串不好操作,所以只能在模式串里进行查找最大相等前后缀
0 0 1 2 0 这就是它的最大相等前后缀,它有什么用呢?
模式串:abcab 文本串:abcacababcab
它的最大前后缀为 0 0 0 1 2
我们来模拟一遍查找
到模式串第五个字符时不同,这时我们不用把文本串的指针回退,只需要在模式串里找到与失配的字符相同的就可以了,怎么找,根据之前的最大相等前后缀来查找,模式串下有个2,只需模式串回退到第二个字符继续判断,如果还是不相等下标0,回退到第一个字符重新查找。这就是KMP算法,相比于朴素算法,KMP是线性的查找节约了大量的时间,最后我们来看看带代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char a[1000010],b[1000010];
int next[1000010];
int k,k1;
void getnext()//最大相等前后缀的初始值
{
next[0]=0;
int i=1,j=0;
while(i<k1)
{
if(b[i]==b[j])
{
next[i++]=++j;
}
else
{
if(j==0)
{
next[i++]=0;
}
else
{
j=next[j-1];
}
}
}
}
int main()
{
scanf("%s%s",a,b);
k=strlen(a),k1=strlen(b);
getnext();
int i,j;
i=j=0;
while(i<k)
{
if(a[i]==b[j])//相等下一位
{
++i;
++j;
}
else
{if(j>0)
j=next[j-1];//如果失配,模式串根据下标移到与文本串失配字符相同的下标
else
++i;}//特判,第一位就失配
if(j>=k1)//满足条件,输出
{
printf("%d\n",i-j+1);
j=next[j-1];//j指向了'\0'失配,移动到文本串所指字符的下标
}
}
for(int i=0;i<k1;i++)
printf("%d ",next[i]);
return 0;
}