zoukankan      html  css  js  c++  java
  • Codeforces 1012D AB-Strings 贪心

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF1012D.html

    题目传送门 - CF1012D

    题意

      给定字符串 $s,t$ ,其中只包含小写字母 $a$ 和 $b$ ,而且 $a$ 和 $b$ 至少在任意一个字符串中各出现一次。

      现在允许你执行一种操作:交换 $a$ 的一段前缀和 $b$ 的一段前缀。例如 $s$ 的前缀是取 $s$ 的前 $i$ 个字母,$0leq ileq |s|$ 。

      问至少执行多少次操作,并输出方案。

      $|s|,|t|leq 2 imes 10^5$ 

    题解

      我们先考虑一下如何得到最少的操作次数。

      首先,连续的相同字符显然可以合并。

      然后我们考虑两种基本操作:

      1. 两个串的开头相同。在两个串中分别取偶数长度前缀和奇数长度前缀交换。字符串长度缩减:2 。

      2. 两个串的开头不同。在两个串各取一个奇数长度前缀并交换。字符串长度缩减:2 。

      举例:

      1.  S = "ababab"   T = "ababa"   $Longrightarrow$    S = "abbab"    T = "abaaba"    $Longrightarrow$      S = "abab"    T = "ababa"  

      2.  S = "ababab"   T = "bababa"   $Longrightarrow$    S = "bababbab"    T = "abaa"    $Longrightarrow$      S = "bababab"    T = "aba"

      以上两种操作是缩减字符串长度最快的方式。

      那么,什么时候会使字符串长度缩减速度下降?

      为了方便起见,我们将 S 和 T 中长度较长的称为 A , 长度较短的称为 B ,将 A 的开头字符设为 0 ,另一种字符设为 1 。

      我们来列举一下缩减速率变慢的情况:(先说明一下,下文中诸如 " 将 X 的某某前缀 接到 Y 上 " 这些,表示将 X 的某某前缀与 Y 的长度为 0 的前缀交换)

      1.

        A = 010101……

        B = 0

        方法:① 在 A 中选取长度为奇数的前缀,接到 B 上。② 把 B 接到 A 上。

        缩减: 1

      2.

        A = 01

        B = 01

        方法:不加赘述。(其实和 1 差不多)

        缩减: 1

      3.

        A = 010101……

        B = 1

        方法:① 在 A 中选择长度为偶数的前缀,接到 B 上。② 在 A 中截取奇数长度的前缀,与 B 交换。

        缩减: 1

      

      于是我们需要尽量避免出现这种情况。

      粗略的方法: 每次操作尽量使得操作完毕后两个串的长度近似。(这样使得串的长度尽量不会到 1 )

      对于 第 1、2 种情况,将 B 的开头与 A 的长度为奇数的前缀交换,并使得交换后长度近似。

      对于 第 3 种情况,采用 任意一种方法,并使得交换后长度近似。两种方法效果相同。

      对于两种基本情况,我们可以在短串只取开头一个,长串决策一下截取前缀的长度,使得交换后长度近似。

      于是剩下的东西只需要你读入的时候压缩一下,以及用链表维护一下字符串,大力分类讨论做决策就可以了。

      时间复杂度 $O(n)$ 。最快运行时间 : 78MS

    代码

      下拉准备迎接三块方方的代码!

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=1000005;
    int c[N],v[N],Next[N],cnt_node=0;
    int L=0,R=1,len[2],head[2],n=0,ans[N][2];
    char s1[N],s2[N];
    int new_node(int color,int tot,int nxt){
    	cnt_node++,c[cnt_node]=color,v[cnt_node]=tot,Next[cnt_node]=nxt;
    	return cnt_node;
    }
    void build(int f,char s[]){
    	int n=strlen(s+1),p=new_node(s[1]-'a',1,0);
    	head[f]=p,len[f]=1;
    	for (int i=2;i<=n;i++)
    		if (s[i]==s[i-1])
    			v[p]++;
    		else
    			p=Next[p]=new_node(s[i]-'a',1,0),len[f]++;
    }
    int func0(int x,int a,int b){
    	return abs((a-2*x-1)-(b+2*x));
    }
    int func1(int x,int a,int b){
    	return abs((a-2*x)-(b+2*x-2));
    }
    int func2(int x,int a,int b){
    	return abs((a-2*x-1)-(b+2*x-1));
    }
    int Get_len(int f){
    	int cnt=0;
    	for (int p=head[f];p;p=Next[p])
    		cnt++;
    	return cnt;
    }
    void New_ans(int Lv,int Rv){
    	n++;
    	ans[n][L]=Lv,ans[n][R]=Rv;
    }
    int main(){
    	scanf("%s%s",s1+1,s2+1);
    	build(0,s1),build(1,s2);
    	while (max(len[L],len[R])>1){
    		if (len[L]<len[R])
    			swap(L,R);
    		if (c[head[L]]==c[head[R]]&&len[R]>1&&len[L]>2){
    			int a=len[L],b=len[R],x1=(a-b+2)/4,x2=x1+1;
    			int x=max(1,min(func1(x1,a,b)<=func1(x2,a,b)?x1:x2,a/2));
    			int tot=v[head[L]],p=head[L];
    			for (int i=1;i<=x*2-1;i++)
    				p=Next[p],tot+=v[p];
    			New_ans(tot,v[head[R]]);
    			int hL=head[L],hR=head[R];
    			v[head[L]=Next[p]]+=v[hR];
    			head[R]=hL;
    			Next[p]=Next[Next[hR]];
    			v[p]+=v[Next[hR]];
    			len[L]-=x*2,len[R]+=x*2-2;
    			continue;
    		}
    		else if (c[head[L]]==c[head[R]]){
    			int a=len[L],b=len[R],x1=(a-b-1)/4,x2=x1+1;
    			int x=min(func0(x1,a,b)<=func0(x2,a,b)?x1:x2,(a-1)/2);
    			int tot=v[head[L]],p=head[L];
    			for (int i=1;i<=x*2;i++)
    				p=Next[p],tot+=v[p];
    			New_ans(tot,0);
    			swap(head[R],head[L]);
    			swap(Next[p],head[L]);
    			v[p]+=v[Next[p]];
    			Next[p]=Next[Next[p]];
    			len[L]=(len[L]<3)?(Get_len(L)):(len[L]-(x*2+1));
    			len[R]=(len[R]<3)?(Get_len(R)):(len[R]+(x*2));
    		}
    		else {
    			int a=len[L],b=len[R],x1=(a-b-1)/4,x2=x1+1;
    			int x=min(func2(x1,a,b)<=func2(x2,a,b)?x1:x2,(a-1)/2);
    			int tot=v[head[L]],p=head[L];
    			for (int i=1;i<=x*2;i++)
    				p=Next[p],tot+=v[p];
    			New_ans(tot,v[head[R]]);
    			v[head[R]]+=v[Next[p]];
    			v[p]+=v[Next[head[R]]];
    			swap(Next[head[R]],Next[p]);
    			Next[head[R]]=Next[Next[head[R]]];
    			Next[p]=Next[Next[p]];
    			swap(head[L],head[R]);
    			len[L]=(len[L]<3)?(Get_len(L)):(len[L]-(x*2+1));
    			len[R]=(len[R]<3)?(Get_len(R)):(len[R]+(x*2-1));
    		}
    	}
    	printf("%d
    ",n);
    	for (int i=1;i<=n;i++)
    		printf("%d %d
    ",ans[i][0],ans[i][1]);
    	return 0;
    }
    

      

  • 相关阅读:
    CMake命令笔记
    在Win10上,Android Studio检测不到设备的解决方案
    在MFC中使用大漠插件
    Win10更新后,IE和Edge以外的浏览器打开网页速度慢的解决方案
    jsp的自定义标签
    js和JQuery区别
    POI (Apache POI)
    TCP程序设计基础
    传参在mybatis的sql映射文件中正确获取
    I/O(输入/输出)
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/CF1012D.html
Copyright © 2011-2022 走看看