F - Yet Another Substring Reverse
题意:给出一个字符串,有一次逆置任意子串的机会,询问一个最长子串的长度,要求子串每一个字母都不相同。
题解:问题可以看成找两个不相交的子串,不同字母个数之和最大。因为不同字符个数最大为 20 20 20,考虑预处理出每一个区间的值,并维护每一个子集的最大值(也就是连续且不同字符个数最多),然后枚举两两子集之和即可。
代码
#include<bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
#define dbg(args...) \
do{ \
cout << "\033[32;1m" << #args << " -> "; \
err(args); \
} while(0)
#else
#define dbg(...)
#endif
void err()
{
cout << "\033[39;0m" << endl;
}
template <template <typename...> class T, typename t, typename... Args>
void err(T<t> a, Args... args)
{
for (auto x : a) cout << x << ' ';
err(args...);
}
template <typename T, typename... Args>
void err(T a, Args... args)
{
cout << a << ' ';
err(args...);
}
/****************************************************************************************************/
string s;
int dp[1 << 20];
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
cin >> s;
int n = s.size();
for(int i = 0; i < n; ++i) {
int used = 0;
for(int j = i; j < n && j - i < 20; ++j) {
int c = s[j] - 'a';
if((used >> c) & 1) break;
used |= 1 << c;
dp[used] = j - i + 1;
}
}
for(int i = 1; i < 1 << 20; ++i) {
for(int j = 0; j < 20; ++j) {
if(!((i >> j) & 1)) {
//每一个子集的最大值
dp[i | 1 << j] = max(dp[i | 1 << j], dp[i]);
// dp[i] = max(dp[i], dp[i ^ (1 << j)]);
}
}
}
int S = 1 << 20, ans = dp[S - 1];
for(int i = 1; i < 1 << 20; ++i) {
int mask = i ^ (S - 1);
ans = max(ans, dp[i] + dp[mask]);
}
cout << ans << '\n';
return 0;
}