美团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 '
'
#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
", ans);
	}
}
原文地址:https://www.cnblogs.com/uid001/p/11109285.html