Codeforces 1012D AB-Strings 贪心
原文链接https://www.cnblogs.com/zhouzhendong/p/CF1012D.html
题目传送门 - CF1012D
题意
给定字符串 $s,t$ ,其中只包含小写字母 $a$ 和 $b$ ,而且 $a$ 和 $b$ 至少在任意一个字符串中各出现一次。
现在允许你执行一种操作:交换 $a$ 的一段前缀和 $b$ 的一段前缀。例如 $s$ 的前缀是取 $s$ 的前 $i$ 个字母,$0\leq i\leq |s|$ 。
问至少执行多少次操作,并输出方案。
$|s|,|t|\leq 2\times 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",n);
for (int i=1;i<=n;i++)
printf("%d %d\n",ans[i][0],ans[i][1]);
return 0;
}
Codeforces 1012D AB-Strings 贪心的更多相关文章
- codeforces 704B - Ant Man 贪心
codeforces 704B - Ant Man 贪心 题意:n个点,每个点有5个值,每次从一个点跳到另一个点,向左跳:abs(b.x-a.x)+a.ll+b.rr 向右跳:abs(b.x-a.x) ...
- CodeForces - 50A Domino piling (贪心+递归)
CodeForces - 50A Domino piling (贪心+递归) 题意分析 奇数*偶数=偶数,如果两个都为奇数,最小的奇数-1递归求解,知道两个数都为1,返回0. 代码 #include ...
- Educational Codeforces Round 12 C. Simple Strings 贪心
C. Simple Strings 题目连接: http://www.codeforces.com/contest/665/problem/C Description zscoder loves si ...
- Codeforces 665C Simple Strings【暴力,贪心】
题目链接: http://codeforces.com/contest/665/problem/C 题意: 改变最少的字符,使得最终序列无相同的连续的字符. 分析: 对每一个与前一个字符相同的字符,枚 ...
- Codeforces 825D Suitable Replacement - 贪心 - 二分答案
You are given two strings s and t consisting of small Latin letters, string s can also contain '?' c ...
- codeforces 721B B. Passwords(贪心)
题目链接: B. Passwords time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- Codeforces 161 B. Discounts (贪心)
题目链接:http://codeforces.com/contest/161/problem/B 题意: 有n个商品和k辆购物车,给出每个商品的价钱c和类别t(1表示凳子,2表示铅笔),如果一辆购物车 ...
- CodeForces 176A Trading Business 贪心
Trading Business 题目连接: http://codeforces.com/problemset/problem/176/A Description To get money for a ...
- Codeforces Gym 100803C Shopping 贪心
Shopping 题目连接: http://codeforces.com/gym/100803/attachments Description Your friend will enjoy shopp ...
随机推荐
- Js -----后台json数据,前端生成下载text文件
需要引入 <script src="/assets/libs/single_file/jquery.min.js"></script> <script ...
- LINUX用户、组、权限管理和归档压缩、时间、Ping
一.用户与用户组管理.权限 1.用户文件/etc/passwd 2.用户密码/etc/shadow 3.组文件/etc/group 4.查看用户和组信息命令id 5.添加用户 useradd [-u ...
- 4)协程一(yeild)
一:什么协程 协程: coroutine/coro - 轻量级线程(一个线程) - 调度由用户控制 - 有独立的寄存器上下文和栈 - 切换时保存状态,回来时恢复 二:协程和多线程比较 协程: coro ...
- python-进程池与线程池,协程
一.进程池与线程池 实现并发的手段有两种,多线程和多进程.注:并发是指多个任务看起来是同时运行的.主要是切换+保存状态. 当我们需要执行的并发任务大于cpu的核数时,我们需要知道一个操作系统不能无限的 ...
- 清北学堂 清北-Day5-R2-xor
有 $ n $ 个物品,每个物品有两个属性 $ a_i,b_i $ ,挑选出若干物品,使得这些物品 $ a_i $ 的异或和 $ x \le m \(.问在这一限制下,\) b_i $ 的总和最大可能 ...
- 设置 Confluence 6 外部索引站点
Confluence 并不能比较容易的对外部站点进行搜索,这个是因为 Confluence 使用的是 Lucene 内部查找,但是你还是有下面 2 个可选的方案: 嵌入外部页面到 Confluence ...
- leetcode(js)算法605之种花问题
假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有.可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去. 给定一个花坛(表示为一个数组包含0和1,其中0表示没种植花,1表示种植了花 ...
- 【python】kafka在与celery和gevent连用时遇到的问题
前提:kafka有同步,多线程,gevent异步和rdkafka异步四种模式.但是在与celery和gevent连用的时候,有的模式会出错. 下面是我代码运行的结果. 结论:使用多线程方式! 使用同步 ...
- java-HTML&javaSkcript&CSS&jQuery&ajax
CSS 伪装 1.<style>a;link{color:#000000} a:visited{color:#000000; a.:hover{color:#FF00FF} a:acti ...
- bzoj 2301
一道莫比乌斯反演入门题. 首先观察题目要求:的数对数 首先可以发现,这个东西同时有上界和下界,所以并不是很容易计算 那么我们变下形,可以看到:原式= 是不是清晰很多了?(当然没有!) 不,这一步很重要 ...