列表

详情


NC13248. 合并字符串的价值

描述

输入两个字符串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中价值最大的字符串,输出这个最大价值即可。

输入描述

第一行一个整数T(T ≤ 500)。 接下来2T行,每行一个字符串,每两行代表一对字符串a和b(|a|,|b|<=100,000;∑(|a|+|b|)<=500,000),字符串的字符集为{A,C,G,T}。

输出描述

对于每组数据输出一行,一个整数表示价值最大的c的价值。

示例1

输入:

2
ACGT
ACGT
AACCGGTT
ACACAGAT

输出:

4
7

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 113ms, 内存消耗: 4300K, 提交时间: 2019-08-16 18:28:21

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 100005
#define ls(x) x<<1
#define rs(x) (x<<1)|1
char s[maxn], t[maxn];
int n, m, mx[4*maxn], tag[4*maxn];
int a[maxn], tot[4],num[4], pos[4][maxn],nw[4];
int get(char ch){
    if(ch == 'A') return 0;
    else if(ch == 'C') return 1;
    else if(ch == 'G') return 2;
    else return 3;
}

void pushup(int rt){
   mx[rt] = max(mx[ls(rt)],mx[rs(rt)])+tag[rt];
}
                

void build(int rt,int l,int r){
    tag[rt] = 0;
    if(l == r){
        mx[rt] = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(ls(rt),l,mid);
    build(rs(rt),mid+1,r);
    pushup(rt);
}

void update(int rt,int l,int r,int L,int R,int v){
    if(L <= l && r <= R){
        mx[rt] += v;
        tag[rt] += v;
        return;
    }
    int mid = (l + r) >> 1;
    if(L <= mid) update(ls(rt),l,mid,L,R,v);
    if(R > mid) update(rs(rt),mid+1,r,L,R,v);
    pushup(rt);
}

int main(){
    int T;
    cin>>T;
    while(T--){
        memset(tot,0,sizeof(tot));
        memset(num,0,sizeof(num));
        scanf("%s%s",s+1,t+1);
        n = strlen(s+1), m = strlen(t+1);
        for(int i = 1;i <= n;i++) tot[get(s[i])]++;
        for(int i = 1;i <= m;i++) tot[get(t[i])]++;
        for(int c, i = 0;i <= n;i++){
            if(i) c = get(s[i]), pos[c][++num[c]] = i;
            for(int j =a[i] = 0;j < 4;j++) a[i] += min(num[j],tot[j] - num[j]);
        }
        build(1,0,n);
        memset(nw,0,sizeof(nw));
        int ans = 0;
        for(int i = 1;i <= m;i++){
            ans = max(ans,mx[1]);
            int c = get(t[i]);
            nw[c]++;
            int p = tot[c]/2 - nw[c] + 1;
            if(p > 0) update(1,0,n,0,p<=num[c]?pos[c][p]-1:n,1);
            p = (tot[c]+1)/2-nw[c]+1;
            if(p <= num[c]) update(1,0,n,p>0?pos[c][p]:0,n,-1);
        }
        printf("%d\n",max(ans,mx[1]));
    }
    return 0;
}

C++(g++ 7.5.0) 解法, 执行用时: 112ms, 内存消耗: 3696K, 提交时间: 2023-07-09 20:35:48

#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
const int M=2e6;
const int mod=998244353;
const int INF=0x3f3f3f3f;
int T,n,m;
int cnt[4],idx[505];
int pos[4][N+5],num[4],a[N+5];
int cur[4],tree[M+5],lazy[M+5];
char s[N+5],t[N+5];
void build(int x,int l,int r){
	lazy[x]=0;
	if(l==r){
		tree[x]=a[l];
		return;
	}
	int mid=(l+r)/2;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	tree[x]=max(tree[x<<1],tree[x<<1|1]);
}
void pushdown(int x){
	int z=lazy[x];
	if(!z)return;
	lazy[x<<1]+=z;
	lazy[x<<1|1]+=z;
	tree[x<<1]+=z;
	tree[x<<1|1]+=z;
	lazy[x]=0;
}
void update(int x,int l,int r,int L,int R,int val){
	if(L<=l && r<=R){
		tree[x]+=val;
		lazy[x]+=val;
		return;
	}
	pushdown(x);
	int mid=(l+r)/2;
	if(L<=mid)update(x<<1,l,mid,L,R,val);
	if(R>mid)update(x<<1|1,mid+1,r,L,R,val);
	tree[x]=max(tree[x<<1],tree[x<<1|1]);
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	idx['A']=0,idx['C']=1;
	idx['G']=2,idx['T']=3;
	cin>>T;
	while(T--){
		cin>>(s+1)>>(t+1);
		n=strlen(s+1),m=strlen(t+1);
		for(int i=1;i<=n;i++)cnt[idx[s[i]]]++;
		for(int i=1;i<=m;i++)cnt[idx[t[i]]]++;
		for(int i=1;i<=n;i++){
			int c=idx[s[i]];
			pos[c][++num[c]]=i;
			for(int j=0;j<4;j++)
				a[i]+=min(num[j],cnt[j]-num[j]);
		}
		build(1,0,n);
		int ans=tree[1];
		for(int i=1;i<=m;i++){
			int c=idx[t[i]];
			cur[c]++;
			int x=cnt[c]/2-cur[c]+1;
			if(x>0)
				update(1,0,n,0,x<=num[c]?pos[c][x]-1:n,1);
			x=(cnt[c]+1)/2-cur[c]+1;
			if(x<=num[c])
				update(1,0,n,x>0?pos[c][x]:0,n,-1);
			ans=max(ans,tree[1]);
		}
		cout<<ans<<"\n";
		memset(cnt,0,sizeof(cnt));
		memset(num,0,sizeof(num));
		memset(cur,0,sizeof(cur));
		for(int i=1;i<=n;i++)a[i]=0;
	}
	return 0;
}

C++(clang++ 11.0.1) 解法, 执行用时: 578ms, 内存消耗: 3836K, 提交时间: 2023-01-15 19:00:29

#include<bits/stdc++.h>
using namespace std;
char str[2][110000];
int n[2],sum[2][4][110000],ans;
int change(char ch)
{
	if(ch=='A')
	   return 0;
    if(ch=='T')
       return 1;
    if(ch=='G')
       return 2;
    if(ch=='C')
       return 3;
    return -1;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%s%s",str[0],str[1]);
		int i,j,s,p,q;
		for(i=0;i<2;i++)
		{
			n[i]=strlen(str[i]);
			memset(sum[i][0],0,sizeof(sum[i][0]));
			for(j=0;j<n[i];j++)
			{
				for(s=0;s<4;s++)
				   sum[i][s][j+1]=sum[i][s][j];
	            sum[i][change(str[i][j])][j+1]++;
			}
		}
		int ch;
		ans=0;
		for(i=0;i<=n[0];i++)
		{
			int jmin,jmax;
			if(i==0)
			{
				jmin=0;
				jmax=n[1];
			}
			else
			{
				jmin=max(0,ch-200);
				jmax=min(n[1],ch+200);
			}
			int awp=0;
			for(j=jmin;j<=jmax;j++)
			{
				 int now=0;
				 for(s=0;s<4;s++)
 					now+=min(sum[0][s][i]+sum[1][s][j],sum[0][s][n[0]]-sum[0][s][i]+sum[1][s][n[1]]-sum[1][s][j]);
 				 if(awp<now)
 				 {
 				 	awp=now;
 				 	ch=j;
 				 }
			}
			if(ans<awp)
			   ans=awp;
		}
		printf("%d\n",ans);
	} 
	return 0;
}

上一题