D3:
T1:买东西
题意:假期到了,小 A 因为期末考试考的好,所以获得了奖金 n 元。现在他来到了
超市,想要买些自己喜欢的东西。超市里有 m 种商品,每一样商品都有他对应
的价值和小 A 对它的喜爱值,且都有无数件,小 A 希望用这些钱买到的东西喜爱值最高。
Input
共两行
第一行两个整数 n m,分别为奖金钱数和超市商品件数。
接下来𝑚行,第𝑖 + 1行两个整数,分别对应第𝑖件商品的价值𝑣𝑖和小 A 的喜爱值𝑎𝑖
Output
一个整数,小 A 买到的物品的最大喜爱值。
Hint
30% 𝑛 ≤ 100, 𝑚 ≤ 10
100% 𝑛 ≤ 1000, 𝑚 ≤ 1000, 0 < 𝑣𝑖 < 100000, 0 < 𝑎𝑖 < N
思路:完全背包板子题
代码:
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
using namespace std;
int n,m ,v[1010];
long long a[1010],dp[1010];
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;i++){
scanf("%d%lld",&v[i],&a[i]);
}
for(int i = 1;i <= m;i++){
for(int j = v[i];j <= n;j++){
dp[j] = max(dp[j],dp[j - v[i]] + a[i]);
}
}
printf("%lld\n",dp[n]);
return 0;
}
T2:滑动窗口
题意:给定一个由小写字母构成的字符串,求不包含重复字母的最长子串长度。子
串的定义为字符串中连续的一部分,如对 abcde 来说,bcd 是子串,但 ace 不
是。如对于 aabcdcda 来说,不包含重复字母的最长子串是 abcd,长度为 4。
Input
一行,为输入的字符串 s。
Output
一个整数,为不包含重复字母的最长子串长度。
Hint
40% s 的长度<=1000
100% s 的长度<=10000000
思路:解法如题目:滑动窗口。
枚举每一位字符,用cnt数组记录字符情况,如果有重复,记录最优解,然后从记录起始字串位置向后枚举,清除cnt记录直到找到与当前字符相同的位置,由此往复,直到字符串枚举完毕。
代码:
#include<cstdio>
#include<iostream>
using namespace std;
string s;
int cnt[300];
int main(){
cin >> s;
int l = s.length(),st = 0,ans = 0;
for(int i = 0;i < l;i++){
if(cnt[s[i]]){
ans = max(ans, i - st);
while(s[st] != s[i])
cnt[s[st++]] = 0;
st++;
}
cnt[s[i]] = 1;
}
ans = max(l - st,ans);
printf("%d\n",ans);
return 0;
}
T3:最长回文字符串
题意:回文字符串的定义是正着写和倒着写一样的字符串,如回文串 abcba 正着
和倒着都是 abcba,而 abcd 倒过来是 dcba,就不是回文字符串。现在给出一个
由字母构成的字符串 s。要求输出这个字符串 s 中最长的回文子串的长度 l。
Input
一行,字符串 s
Output
一行一个整数,最长回文子串的长度 l
Hint
70% 𝑛 ≤ 1000
100% 𝑛 ≤ 1000000
思路:若本题使用暴力算法,一定会超时,因此考虑马拉车算法。
马拉车算法:首先先在每个字符之间插入原字符串中不可能出现的字符(与本题如’#‘,’$‘,’@'等),将所有回文字符串长度变为奇数,然后定义数组p,整数mi和right,p[i]表示以i为中心的回文字符串半径,mi与right分别表示目前右端点最靠右的回文字符串中心和半径
接下来从字符串起始字符开始枚举,设当前枚举位置为i:
当right>i时,如下图:
a # b # c # b #c# b # a #b#c#b#c#
2mi-i mi i right
那么可以保证i到mi一定与mi到(2mi-i)之间的字符一定对称
但是如果i到right的距离小于p[2 * mi - i],则不能保证right到p[2mi-i]+i之间的字符与2mi-i与p[2mi-i]之间的字符对称,则p[i]等于right-i,反之p[i]等于p[2*mi-i]
当right<=i时,无法保证i到right之间的字符对称,所以p[i]等于1
然后进行暴力扩张,之后记录最大值输出即可
代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxstr = 1000100;
char c[maxstr],a[maxstr * 2 + 10];
int p[maxstr * 2 + 10];
int main(){
scanf("%s",c + 1);
a[0] = '$';
int len = strlen(c + 1);
for(int i = 1;i <= len;i++){
a[i * 2] = c[i];
}
for(int i = 1;i <= len;i++){
a[i * 2 - 1] = '#';
}
len = len * 2 + 2;
a[len - 1] = '#';
a[len] = '\0';
int mi = 0,right = 0;
int maxpoint = 0, maxlen = 0;
for(int i = 1;i < len;i++){
p[i] = right > i ? min(p[2 * mi - i],right - i) : 1;
while(a[i + p[i]] == a[i - p[i]])p[i]++;
if(right < i + p[i]){
right = i + p[i];
mi = i;
}
if(maxlen < p[i]){
maxlen = p[i];
maxpoint = i;
}
}
printf("%d\n",maxlen - 1);
return 0;
}