zoukankan      html  css  js  c++  java
  • 美团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);
    	}
    }
    
  • 相关阅读:
    Java对象的生命周期与作用域的讨论(转)
    [置顶] Oracle学习路线与方法
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
  • 原文地址:https://www.cnblogs.com/uid001/p/11109285.html
Copyright © 2011-2022 走看看