D3题目及思路

本文介绍了利用动态规划和滑动窗口解决字符串处理问题的典型例题,包括寻找购买商品最大喜爱值的问题、找出不包含重复字母的最长子串长度以及找到最长回文子串的长度。通过示例代码详细阐述了马拉车算法在回文串查找中的应用,展示了如何高效地解决这类问题。
摘要由CSDN通过智能技术生成

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值