美团CodeM初赛B轮 合并字符串的价值 (线段树,分类讨论)
输入两个字符串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); } }