输入两个字符串a和b,合并成一个串c,属于a或b的字符在c中顺序保持不变。如"ACG"和"UT"可以被组合成"AUCTG"或"ACUGT"等。
我们定义字符串c的价值如下:令n为字符串c的长度,分界线k(1<=k<=n-1)将c分为两个子串u=c[1..k],v=c[k+1..n]。u、v中字符的任意排列,使得u、v的最长公共前缀最大,这就是分界线k的价值,而所有分界线k价值最大的一个为字符串c的价值。
比如,字符串c=ACGTTTGCAT的价值为5,因为将该串分成两半得到u=ACGTT,V=TGCAT,重新排列后可以使得u=v,即最长公共前缀为5。
你需要求出所有可能的c中价值最大的字符串,输出这个最大价值即可。

官方题解如下.

其实就是枚举$a$划分进左侧的位置, 对于$b$的划分可以分成连续的五段, 每段贡献的正负号是相同的, 用线段树对每段求最大值即可.

#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <math.h>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <string.h>
#include <bitset>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std; const int N = 1e6+10;
char a[N], b[N];
int f[N], ff[N];
int s1[N][4], s2[N][4]; int ID(char x) {
if (x=='A') return 0;
if (x=='C') return 1;
if (x=='G') return 2;
return 3;
} int cnt[N<<2][16]; void build(int o, int l, int r) {
if (l==r) {
REP(i,0,15) {
cnt[o][i] = 0;
REP(j,0,3) {
if (i>>j&1) cnt[o][i]+=s2[l][j];
else cnt[o][i]-=s2[l][j];
}
}
return;
}
build(ls),build(rs);
REP(i,0,15) cnt[o][i]=max(cnt[lc][i],cnt[rc][i]);
}
int query(int o, int l, int r, int ql, int qr, int mask) {
if (ql<=l&&r<=qr) return cnt[o][mask];
if (mid>=qr) return query(ls,ql,qr,mask);
if (mid<ql) return query(rs,ql,qr,mask);
return max(query(ls,ql,qr,mask),query(rs,ql,qr,mask));
} int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%s%s", a+1, b+1);
int n = strlen(a+1), m = strlen(b+1);
REP(i,1,n) {
memcpy(s1[i],s1[i-1],sizeof s1[0]);
++s1[i][ID(a[i])];
}
REP(i,1,m) {
memcpy(s2[i],s2[i-1],sizeof s2[0]);
++s2[i][ID(b[i])];
}
build(1,0,m);
int ans = 0;
REP(i,8,n) {
REP(c,0,3) {
int L = s1[i][c], R = s1[n][c]-L;
int l = 0, r = m, k = -1;
while (l<=r) {
if (L+s2[mid][c]<=R+s2[m][c]-s2[mid][c]) k=mid,l=mid+1;
else r=mid-1;
}
f[c] = ff[c] = k;
}
sort(f, f+4), f[4] = m;
REP(c,0,4) {
int l = 0, r = f[c];
if (c) l = f[c-1]+1;
if (l<=r) {
int sum = 0, mask = 0;
REP(c,0,3) {
if (r<=ff[c]) sum+=s1[i][c],mask^=1<<c;
else sum+=s1[n][c]-s1[i][c]+s2[m][c];
}
ans = max(ans, sum+query(1,0,m,l,r,mask));
}
}
}
printf("%d\n", ans);
}
}

美团CodeM初赛B轮 合并字符串的价值 (线段树,分类讨论)的更多相关文章

  1. P5979 [PA2014]Druzyny dp 分治 线段树 分类讨论 启发式合并

    LINK:Druzyny 这题研究了一下午 终于搞懂了. \(n^2\)的dp很容易得到. 考虑优化.又有大于的限制又有小于的限制这个非常难处理. 不过可以得到在限制人数上界的情况下能转移到的最远端点 ...

  2. #6164. 「美团 CodeM 初赛 Round A」数列互质-莫队

    #6164. 「美团 CodeM 初赛 Round A」数列互质 思路 : 对这个题来言,莫队可以 n*根号n 离线处理出各个数出现个的次数 ,同时可以得到每个次数出现的次数 , 但是还要处理有多少 ...

  3. 【CodeM初赛B轮】F 期望DP

    [CodeM初赛B轮]F 题目大意:有n个景点,m条无向边,经过每条边的时间需要的时间是li,在第i个景点游览花费的时间是ti,游览完第i个景点可以获得的满意度是hi.你的总时间为k,起初你等概率的选 ...

  4. 【CodeM初赛B轮】A 贪心

    [CodeM初赛B轮]A 题目大意:给你一棵树,起初所有点都是白色的,你每次都能选择一个白点i,将这个点i到根路径上的所有到i的距离<k[i]的点都染成黑色(根和i也算,已经被染成黑色的点还是黑 ...

  5. 「美团 CodeM 初赛 Round A」试题泛做

    最长树链 树形DP.我们发现gcd是多少其实并不重要,只要不是1就好了,此外只要有一个公共的质数就好了.计f[i][j]表示i子树内含有j因子的最长链是多少.因为一个数的不同的质因子个数是log级别的 ...

  6. 51Nod1553 周期串查询 字符串 哈希 线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1553.html 题目传送门 - 51Nod1553 题意 有一个串只包含数字字符.串的长度为n,下标 ...

  7. HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)

    Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Tota ...

  8. P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)

    显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...

  9. 【CodeM初赛A轮】D 分解质因数+暴力

    题目描述树链是指树里的一条路径.美团外卖的形象代言人袋鼠先生最近在研究一个特殊的最长树链问题.现在树中的每个点都有一个正整数值,他想在树中找出最长的树链,使得这条树链上所有对应点的值的最大公约数大于1 ...

随机推荐

  1. ZR#954 分组

    ZR#954 分组 解法: 设 $ f[i][a][b] $ 表示考虑了排序后的前 $ i $ 个人,目前已经有 $ a $ 个组配好了,还有 $ b $ 个组只有组员没有组长的最小代价.转移时,考虑 ...

  2. @EnableTransactionManagement的使用

    Spring Boot 使用事务非常简单,首先使用注解 @EnableTransactionManagement 开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactio ...

  3. Ubuntu下Nginx的安装和卸载

    环境是Ubuntu 16.04 安装: sudo apt-get update sudo apt-get install nginx 卸载: sudo apt-get --purge remove n ...

  4. idhttp访问HTTPS

    idhttp访问HTTPS 访问一个 WEB 网站,如果采用 HTTP 的话,直接使用 TIdHTTP 这个控件,最简单的用法是: S := IdHTTP1.Get('www.qq.com'); 这里 ...

  5. jQuery源码解读----part 2

    分离构造器 通过new操作符构建一个对象,一般经过四步: A.创建一个新对象 B.将构造函数的作用域赋给新对象(所以this就指向了这个新对象) C.执行构造函数中的代码 D.返回这个新对象 最后一点 ...

  6. kotlin嵌套类

    就是类中定义类 package loaderman.demo class Outer { var name: String = "name" inner class inner { ...

  7. C之内存地址

    计算机的内存地址 * 32位系统最多能识别4G内存 * 32位系统的地址总线长度是32位的,也就是说能分配给内存地址的数字是 2的32次方个 * 内存中每一个字节都需要一个内存地址 * 一个数字对用一 ...

  8. php操作成功返回当前页并刷新

    echo "<script>alert('操作成功');location.href='".$_SERVER["HTTP_REFERER"].&quo ...

  9. ckpt convert to pb

    import tensorflow as tf #from create_tf_record import * from tensorflow.python.framework import grap ...

  10. 阶段5 3.微服务项目【学成在线】_day03 CMS页面管理开发_10-修改页面-前端-修改页面

    1.进入页面,通过钩子方法请求服务端获取页面信息,并赋值给数据模型对象 2.页面信息通过数据绑定在表单显示 3.用户修改信息点击“提交”请求服务端修改页面信息接口 3.3.3 修改页面 3.3.3.1 ...