输入两个字符串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);
}
}