题目链接:传送门

思路:

由于只能翻转一次子串,就相当于找出两个不连续的子串,把在后面的一个子串翻转过来,和第一个子串拼接。

因为题目仅要求子串中的字符不重复,所以字符的先后顺序无关,翻转的操作就相当于:

选出两个不连续的子串,且他们没有相同的字符,两个子串的长度之和就是答案的一种可能。

题目中反复强调,给出的字符串只有前20个字母[a, t],考虑到$2^{20} = 10^{6}, 2^{26} = 6*10^{7}$,显然在疯狂暗示:要用状压来做这题。

所以考虑二进制状压字符集合。


一个朴素的想法

令集合X = {'a', 'b',..., 't'},用|X|表示集合X的大小。

预处理出集合X的所有有效子集(在原字符串中能找得到)。时间复杂度为O(n*|X|) = 2*$10^{6}$。

然后再枚举X的子集A,和集合A在X中的补集B的子集C,若C是有效的(在原字符串中能找到),则|A|+|C|就是答案的一种可能。

这样做的总时间复杂度是O($2^{|X|}* 2^{|X|}$ + n*|X|) = 1e12,显然会TLE。


题解:

实际上,我们在枚举集合B的子集C的时候,如果我们能知道集合B的有效子集的大小的最大值max{|C|},就可以用|A|+max{|C|}以O(1)的时间来更新答案了。时间复杂度可以下降到O($2^{|X|}$)

接下来考虑如何预处理出max{|C|}。

如果用f[mask]表示,以mask二进制表示的集合S的最大有效子集的大小,那么:

如果S是有效的:f[mask] = |S|

否则:f[mask] = max{f[mask^(1<<i)] | 0 < i < |X| && mask&(1<<i) > 0}

这里的处理是$O(|X|*2^{|X|}) = 2*10^{7}$,是可行的。


代码:$O(|X|*2^{|X|} + |X|*n)$

 #include <bits/stdc++.h>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 100005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x)
#define sz(x) ((int)x.size())
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x) using namespace std;
typedef long long ll;
typedef double db; /** fast read **/
template <typename T>
inline void read(T &x) {
x = ; T fg = ; char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') fg = -;
ch = getchar();
}
while (isdigit(ch)) x = x*+ch-'', ch = getchar();
x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
#define MAXMASK 20 int f[mk(MAXMASK)]; // f[mask] = mask's max number of different characters
int main()
{
string s;
cin >> s; int n = s.size();
for (int i = ; i < n; i++) {
int mask = ;
for (int j = ; j < MAXMASK && i+j < n; j++) {
int b = s[i+j] - 'a';
if (mask & mk(b))
break;
mask |= mk(b);
f[mask] = j+;
}
}
for (int mask = ; mask < mk(MAXMASK); mask++) {
for (int i = ; i < MAXMASK; i++) if (mask & mk(i)){
f[mask] = max(f[mask], f[mask ^ mk(i)]);
}
}
int ans = ;
for (int mask = ; mask < mk(MAXMASK); mask++) {
int mask1 = (mk(MAXMASK)-) ^ mask;
ans = max(ans, f[mask] + f[mask1]);
}
cout << ans << endl; return ;
}

Codeforces1234F. Yet Another Substring Reverse(状压dp)的更多相关文章

  1. fzu2188 状压dp

    G - Simple String Problem Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & ...

  2. HDU 1074 Doing Homework【状压DP】

    Doing Homework Problem Description Ignatius has just come back school from the 30th ACM/ICPC. Now he ...

  3. 【XSY2745】装饰地板 状压DP 特征多项式

    题目大意 你有\(s_1\)种\(1\times 2\)的地砖,\(s_2\)种\(2\times 1\)的地砖. 记铺满\(m\times n\)的地板的方案数为\(f(m,n)\). 给你\(m, ...

  4. Codeforces Beta Round #8 C. Looking for Order 状压dp

    题目链接: http://codeforces.com/problemset/problem/8/C C. Looking for Order time limit per test:4 second ...

  5. 状压DP的总结

    状压dp的标志 ①数据小 ②通过题目所给出的条件以后得到的特征集合小 一:CF259div2 D: 题目大意:保证b[i]中每个数互质,给出a[i],然后求1~n的abs(a[i]-b[i])最小.a ...

  6. UVa 1204 Fun Game (状压DP)

    题意:有一些小孩(至少两个)围成一圈,有 n 轮游戏,每一轮从某个小孩开始往左或者往右伟手帕,拿到手帕写上自己的性别(B,G),然后以后相同方向给下一个. 然后在某个小孩结束,给出 n 轮手帕上的序列 ...

  7. FZU - 2218 Simple String Problem(状压dp)

    Simple String Problem Recently, you have found your interest in string theory. Here is an interestin ...

  8. 状压DP之LGTB 与序列

    题目 思路 这道题竟然是状压DP,本人以为是数论,看都没看就去打下一题的暴力了,哭 \(A_i\)<=30,所以我们只需要考虑1-58个数,再往后选的话还不如选1更优,注意,1是可以重复选取的, ...

  9. 7月15日考试 题解(链表+状压DP+思维题)

    前言:蒟蒻太弱了,全打的暴力QAQ. --------------------- T1 小Z的求和 题目大意:求$\sum\limits_{i=1}^n \sum\limits_{j=i}^n kth ...

  10. Atcoder Regular Contest 093 D - Dark Horse(组合数学+状压 dp)

    Atcoder 题面传送门 & 洛谷题面传送门 常规题,简单写写罢((( 首先 \(1\) 的位置是什么不重要,我们不妨钦定 \(1\) 号选手最初就处在 \(1\) 号位置,最后答案乘个 \ ...

随机推荐

  1. JavaScript-W3School-Browser 对象:Window open() 方法

    ylbtech-JavaScript-Runoob-Browser 对象:Window open() 方法 1.返回顶部 1. Window open() 方法  Window 对象 定义和用法 op ...

  2. Java -- 泛型父类中获取子类的泛型T

    原文:https://blog.csdn.net/u014723529/article/details/70574026 /** * 获取实体类型名称 * 子类可覆盖此方法,返回:泛型T的类名.cla ...

  3. CSS样式div

    页面中,有很多样式标签:div标签,对标签定位的地方有: 1.<head>标签里加<style>标签,在<style>标签中添加样式.如: <style> ...

  4. Jmeter之循环控制器

    在使用Jmeter测试时,部分接口需要循环执行多次,这时候就可以使用循环控制器去控制执行. 循环控制器如下图: 说明 : (1.名称:标识,建议明确此循环控制器的使用的作用是什么(如:登录循环控制) ...

  5. Jmeter之线程组(Stepping和Ultimate)

    jmeter自带的线程组比较简单,如果需要逐渐增加并发数的功能并不能实现,所以就需要使用Jmeter插件--Stepping Thread Group. 一.安装Stepping/UItimate T ...

  6. LoadRunner之参数化

    一.为什么要进行参数化 LoadRunner在录制脚本的时候,只是忠实的记录了所有从客户端发送到服务器的数据,而在进行性能测试的时候,为了更接近真实的模拟现实应用,对于某些信息需要每次提交不同的数据, ...

  7. Windows下GIT的用户密码修改

    Windows下GIT的用户密码修改

  8. JS函数的基础部分

    JS函数的基础部分 JS函数的部分: 先看下一段的代码: window.onload = function(){  function test(){   alert("123"); ...

  9. idea中配置tomcat详细

    1:首先要添加一个tomcat流程 2:配置tomcat: 3:配置tomcat中的deployment(就是配置你需要部署的工程) 4:配置tomcat中需要输出的日志logs 5:启动 tomca ...

  10. 应用安全 - Java Web 应用 - Confluence - 漏洞汇总

    CVE-2019-3395 Date: -- 类型: SSRF 影响范围: Confluence 1.*.*.*.*.3.*.*.4.*.*.5.*.* Confluence 6.0.*.1.*.6. ...