Get an Even String
[Link](Problem - C - Codeforces)
题意
给你一个字符串下标从 1 1 1开始,当且所有的 a i = = a i + 1 ( i % 2 = 1 ) a_i==a_{i+1}(i\%2=1) ai==ai+1(i%2=1)的时候称为好串,你可以删除任意位置字符,问你得到最长好串的操作数是多少。
思路
贪心
对于某一个字符 x x x如果后面直接由和它一样的就拿来,因为这样不会影响后面的字符,或者后面某一个和 x x x前面的配对和 x x x直接和它相邻的配对是一样的。
对于不相邻的我们要将连续连续不相邻的后面最近的配对,例如 a b c d b a a abcdbaa abcdbaa中 a b c d abcd abcd是连续不相邻的,我们要将最靠前的这些里面再次出现的配对,如果不配的话,要不后面没有和前面配对的了,要不就是因为后面的和前面配对导致不能和更后面的配对了。
可以记录一下某个字符离他最近的后面的在哪,然后对于不相邻的我们维护一个这些不相邻的最近的下一个在哪,即可。
Code
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
string str; cin >> str;
n = str.size();
vector<int> f(n + 1);
vector<int> c(26, -1);
for (int i = str.size() - 1; i >= 0; i --) {
f[i] = c[str[i] - 'a'];
c[str[i] - 'a'] = i;
}
int l = - 1, r = -1;
int res = 0;
int i;
for (i = 0; i < n; i ++) {
if (l != -1 && i == r) {
res += 2;
l = -1;
}
else if (i + 1 < n && str[i] == str[i + 1]) {
res += 2, i ++;
l = -1;
}
else if (f[i] != -1){
if (l == -1) {
l = i, r = f[i];
}
else if (i == r) {
res += 2;
l = -1;
}
else {
r = min(r, f[i]);
}
}
}
if (i == n - 1 && str[n - 2] == str[n - 1]) res ++;
cout << (n - res) << '\n';
}
return 0;
}
// 1 1 1 2 3 2 1
简化一下思路,找一下并集,就是从前往后找当前前缀里第一个出现两次的即这个两次的把前边所有的都限制住了,用个 m a p map map搞一下就行。
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
string str; cin >> str;
n = str.size();
int res = 0;
for (int i = 0; i < n; i ++) {
map<int, int> mp;
int j = i;
while (j < n) {
mp[str[j]] ++;
if (mp[str[j]] == 2) {
res += 2;
break;
}
j ++;
}
i = j;
}
cout << n - res << '\n';
}
return 0;
}
d p dp dp
对于每一个字符只有两种情况,删除或者不删,设 f [ i ] : 前 i 个 里 的 最 长 合 法 串 长 , l a s t [ i ] : s t r [ i ] 上 一 次 出 现 的 位 置 f[i]:前i个里的最长合法串长,last[i]:str[i]上一次出现的位置 f[i]:前i个里的最长合法串长,last[i]:str[i]上一次出现的位置,如果当前这个不删除即 f [ i ] = f [ l a s t [ i − 1 ] ] + 2 f[i]=f[last[i - 1]] + 2 f[i]=f[last[i−1]]+2,删除即 f [ i ] = f [ i − 1 ] f[i] = f[i-1] f[i]=f[i−1]。
Code
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
string str; cin >> str;
n = str.size();
vector<int> f(n + 1), last(26, - 1);
for (int i = 1; i <= n; i ++) {
f[i] = f[i - 1];
if (last[str[i - 1] - 'a'] != -1)
f[i] = max(f[i], f[last[str[i - 1] - 'a'] - 1] + 2);
last[str[i - 1] - 'a'] = i;
}
cout << n - f[n] << '\n';
}
return 0;
}