[codeforces1234F]Yet Another Substring Reverse
大致题意为将某个子串进行翻转后,使得不包含相同字符的字符子串长度最长。只能翻转一次或零次。
设一个子串的状态为包含字符的二进制。如子串为$abacd$,则状态为$00000000000000001111$。
根据分析可以得到,一个子串和另一个子串如果没有交集,则两个串可以经过一次翻转合并在一起。
例如:$abcdefga$,串$ab$和串$fg$,可以通过翻转$cdefg$变成$abgfedca$。
所以如果枚举一个状态,再枚举这个状态的补集的子集。就可以得到合法的状态。
但是枚举子集的复杂度太大,所以我们先处理出每种合法状态有多少个字符,然后再从小到大枚举一遍状态。这样可以得到每种状态的合法子集的最大值。
然后计算答案。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 1e5 + 100; 5 int dp[1 << 21], vis[21]; 6 string s; 7 int main() { 8 cin >> s; 9 for (int i = 0; i < s.size(); i++) { 10 int mark = 0, cnt = 0; 11 memset(vis, 0, sizeof(vis)); 12 for (int j = i; j < s.size(); j++) { 13 if (vis[s[j] - 'a']) 14 break; 15 vis[s[j] - 'a'] = 1; 16 mark |= (1 << (s[j] - 'a')); 17 cnt++; 18 dp[mark] = cnt; 19 } 20 } 21 for (int i = 0; i < (1 << 20); i++) 22 for (int j = 0; j < 20; j++) 23 if (i & (1 << j)) 24 dp[i] = max(dp[i], dp[i ^ (1 << j)]); 25 int ans = 0; 26 for (int i = 0; i < (1 << 20); i++) 27 ans = max(ans, dp[i] + dp[i ^ ((1 << 20) - 1)]); 28 printf("%d\n", ans); 29 }