[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 }

 

posted @ 2019-10-04 19:27  祈梦生  阅读(411)  评论(0编辑  收藏  举报