[IOI2000] 回文字串
题目背景
IOI2000 第一题
题目描述
回文词是一种对称的字符串。任意给定一个字符串,通过插入若干字符,都可以变成回文词。此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数。
比如 Ab3bd \verb!Ab3bd! Ab3bd 插入 2 2 2 个字符后可以变成回文词 dAb3bAd \verb!dAb3bAd! dAb3bAd 或 Adb3bdA \verb!Adb3bdA! Adb3bdA,但是插入少于 2 2 2 个的字符无法变成回文词。
注意:此问题区分大小写。
输入格式
输入共一行,一个字符串。
输出格式
有且只有一个整数,即最少插入字符数。
样例 #1
样例输入 #1
Ab3bd
样例输出 #1
2
提示
数据范围及约定
记字符串长度为 l l l。
对于全部数据, 0 < l ≤ 1000 0<l\le 1000 0<l≤1000。
分析
令 d p [ i ] [ j ] dp[i][j] dp[i][j]表示使坐标从j到i的子串变成回文串所需要的最小字符数,当 s [ i ] = = s [ j ] s[i]==s[j] s[i]==s[j]时,此时可以选择添加,此时需要下表从 i i i到 j + 1 j+1 j+1为回文串,则 d p [ i ] [ j ] = d p [ i ] [ j + 1 ] + 1 dp[i][j]=dp[i][j+1]+1 dp[i][j]=dp[i][j+1]+1,或者不添加,则 d p [ i ] [ j ] = d p [ i − 1 ] [ j + 1 ] dp[i][j]=dp[i-1][j+1] dp[i][j]=dp[i−1][j+1],当 s [ i ] ! = s [ j ] s[i]!=s[j] s[i]!=s[j]时,可以选择在 i i i和 j j j处添加,若在 i i i处添加,此时下标 j + 1 j+1 j+1到 i i i得是回文串,则 d p [ i ] [ j ] = d p [ i ] [ j + 1 ] + 1 dp[i][j]=dp[i][j+1]+1 dp[i][j]=dp[i][j+1]+1,同理在 j j j处添加,则 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + 1 dp[i][j]=dp[i-1][j]+1 dp[i][j]=dp[i−1][j]+1,最后取最小的即可。
代码
c
#include<bits/stdc++.h>
using namespace std;
const int N = 1005, INF = 0x3f3f3f3f;
int dp[N][N];
int main() {
string s;
cin >> s;
int n = s.size();
for(int i = 1; i <= n; i ++ ) {
for(int j = i; j >= 1; j -- ) {
if(s[j - 1] == s[i - 1]) {
dp[i][j] = min(dp[i][j + 1] + 1, dp[i - 1][j + 1]);
} else {
dp[i][j] = min(dp[i - 1][j], dp[i][j + 1]) + 1;
}
}
}
cout << dp[n][1];
return 0;
}
[USACO03FALL] Cow Exhibition G
题目背景
题目描述
奶牛想证明它们是聪明而风趣的。为此,贝西筹备了一个奶牛博览会,她已经对 N N N 头奶牛进行了面试,确定了每头奶牛的智商和情商。
贝西有权选择让哪些奶牛参加展览。由于负的智商或情商会造成负面效果,所以贝西不希望出展奶牛的智商之和小于零,或情商之和小于零。满足这两个条件下,她希望出展奶牛的智商与情商之和越大越好,请帮助贝西求出这个最大值。
输入格式
第一行:单个整数 N N N, 1 ≤ N ≤ 400 1 \le N \le 400 1≤N≤400。
第二行到第 N + 1 N+1 N+1 行:第 i + 1 i+1 i+1 行有两个整数: S i S_i Si 和 F i F_i Fi,表示第 i i i 头奶牛的智商和情商,− 1000 ≤ S i ; F i ≤ 1000 1000 \le S_i;F_i \le 1000 1000≤Si;Fi≤1000。
输出格式
输出单个整数:表示情商与智商和的最大值。贝西可以不让任何奶牛参加展览,如果这样做是最好的,输出 0 0 0。
样例 #1
样例输入 #1
5
-5 7
8 -6
6 -3
2 1
-8 -5
样例输出 #1
8
提示
选择第一头,第三头,第四头奶牛,智商和为−5+6+2 = 3,情商和为7−3+1 = 5。再加
入第二号奶牛可使总和提升到10,不过由于情商和变成负的了,所以是不允许的
分析
可以看出这是01背包的变式,令dp[i][j]表示取前i个奶牛,总智商为j的情商的最大值,最后答案只需要遍历所有的dp,获取情商和智商和即可。同普通01背包,状态转移如下
- dp[i][j]=max(dp[i-1][j],dp[i-1][j-w]+v)
但是这里会出现智商为负的情况,导致数组越界,因此可以将dp数组整体右移4e5个单位,最后二维会MLE,需要滚动数组优化一下,还有一个重点,优化成一维时,若体积为负,则可能超过最大体积,此时需要正着遍历
代码
c
#include<bits/stdc++.h>
using namespace std;
const int N = 405, M = 9e5 + 5;
int dp[M]; // dp[i][j] 取i个奶牛,总智商为j,情商的最大值
struct node_ {
int first, second;
}t[N];
int main() {
int n;
cin >> n;
int maxn = 0;
memset(dp, -0x3f, sizeof(dp));
dp[(int)4e5] = 0;
for(int i = 1; i <= n; i ++ ) {
cin >> t[i].first >> t[i].second;
maxn += t[i].first > 0 ? t[i].first : 0;
}
for(int i = 1; i <= n; i ++ ) {
if(t[i].first >= 0) {
for(int j = 8e5; j >= t[i].first; j -- ) dp[j] = max(dp[j], dp[j - t[i].first] + t[i].second);
} else {
for(int j = 0; j <= 8e5 + t[i].first; j ++ ) dp[j] = max(dp[j], dp[j - t[i].first] + t[i].second);
}
}
int res = 0;
for(int i = 4e5; i <= 8e5; i ++ ) {
if(dp[i] > 0)
res = max(res, dp[i] + i - (int)4e5);
}
cout << res << endl;
return 0;
}