题目要求可以转化成一个01串,让通过最少次数把序列变成中间是0,两端是1;

首先我们可以考虑一些性质:

最优解一定是每次操作都把0和1交换

这个很好理解,如果你交换同一种东西,跟没换一样

这个题卡就卡在他是一个环,由于可以两头交换,所以不好处理,我们的做法是破环为链:

对于整个环,在最优解情况下,一定有两个相邻的位置没有被交换过

如果所有相邻位置都换过,那么他就换回去了,也是无效操作,所有我们可以枚举这个点作为断点,把环视为n个序列

断点确定后,我们设置一个目标状态,就是是一种颜色(0或1)全部靠边(考场上我想的是让一种颜色靠到中间,但这样不好维护,也不好优化)

假如我们让0靠到两边,那么问题就变成:每个1靠到两边的操作次数之和

那么再给一个结论:

每个1靠到左边的花费是他左边0的个数,靠到右边是他右边0的个数

我们如果只考虑一个点的话,他要走到最左边,左边已经有一些1了,他要走的就是左边0的个数

那么现在我们就有了一个n2的暴力:

先预处理出2n长度的链的0前缀,后缀和,然后对于每段n长度的链,对其中每个1比较他走到左边和右边的花费,取min累加贡献,再对每个链的答案取最小值就行,这样有40分,前提是少用几个memset或者把数组开小!!

我们考虑优化,我们发现最优决策好像是有分界点的,对于一条n的链,一定是存在某个点,在左边的点都靠到左边,右边的点都靠到右边,这个其实很好想,哪里0少去哪里嘛,所以我们只要找到这个分界点,然后求出前面所有1靠到左边的贡献,后面所有1靠到右面的贡献就行

怎么办?预处理前缀和的前缀和

我们把1之前到i的所有0数量记为sumb[i],把

从1到i之间所有1的花费记为sum[i],我们可以看出来sum就是前缀和的前缀和

for(int i=1;i<=2*n;i++)
{
sumb[i]=sumb[i-1];sum[i]=sum[i-1];sumr[i]=sumr[i-1];
if(a[i]=='B')sumb[i]++;
if(a[i]=='R')sum[i]+=sumb[i-1],sumr[i]++;
}

蒟蒻不会用三目运算符,请见谅

sumr是1到i所有1的个数,一会要用。注意花费是之前的0个数,所以要减1

后缀和什么的也一样,下面就是如何求出差分之后的值了。

因为我们枚举到2n,现在想求从i到j的前缀和,我们看上面这个递推柿子,可以想到

把i到j的1靠到i的花费=把1到j靠到1的花费-把1到i靠到j的花费-i之前的0个数*i到j中间的1个数

就是 $$ans=sum_j-sum_{i-1}-sumb_{i-1}\times(sumr_j-sumr_{i-1}) $$

我们把i当成第一位,前面所有的0都被多算了,中间有几个1就多算了几次,减去

那么我们只有最后一个问题:分界点到底在哪???

我们当然可以二分,nlogn卡常就可过,但是他可以On:

记得上面的一句话:哪里0少往哪里移,所以最优的分界点一定是0的中点,每次取0的中点就行

另一种做法是单调指针,我们发现当区间移动的时候,分界点的移动是单调的;为什么呢?引用Yubai的证明

如果你把左边一个0移到右边,左边优的会变多,右边优的变少,指针不降(右移)

把左边一个1移到右边,只有两头发生了变化,指针不降(不动)

所以满足单调,单调指针扫过去,均摊On

下面本该贴代码结束了,但是此时

玄学做法出现了!

直接将每段序列中点视为分界点,On解决,AC

看上去没有正确性,但是经过一夜对拍之后依然没有Hack掉

实际上,它是正确的

我们考虑最终结果一定是一段连续的01串,那么他可以把1均匀分到两边,这样答案就可以取序列中点。

事实上,通过枚举区间,一定可以使得中点在0的中点区间中出现,而非中点的其他点不一定在中点区间内出现,且离中点越远出现概率越小,即

序列中点一定可以得出正确答案

所以枚举中点正确,而且码量小

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2000050;
char a[N];
int sumb[N],sufb[N],sum[N],suf[N],sumr[N],sufr[N];
inline void clear(int m)
{
for(int i=1;i<=2*m;i++)
sumb[i]=sufb[i]=sum[i]=suf[i]=sumr[i]=sufr[i]=0;
}
signed main()
{
int T;cin>>T;
while(T--)
{
scanf("%s",a+1);
int n=strlen(a+1);
for(int i=1;i<=n;i++)a[i+n]=a[i];
int ans=999999999999;
for(int i=1;i<=2*n;i++)
{
sumb[i]=sumb[i-1];sum[i]=sum[i-1];sumr[i]=sumr[i-1];
if(a[i]=='B')sumb[i]++;
if(a[i]=='R')sum[i]+=sumb[i-1],sumr[i]++;
}
for(int i=2*n;i>=1;i--)
{
sufb[i]=sufb[i+1];suf[i]=suf[i+1];sufr[i]=sufr[i+1];
if(a[i]=='B')sufb[i]++;
if(a[i]=='R')suf[i]+=sufb[i+1],sufr[i]++;
}
for(int i=1;i<=n;i++)
{
int p=i+n-1,j=(i+p)/2;
int qz=sum[j]-sum[i-1]-sumb[i-1]*(sumr[j]-sumr[i-1]),
hz=suf[j]-suf[p+1]-sufb[p+1]*(sufr[j]-sufr[p+1]);
ans=min(ans,qz+hz);
}
printf("%lld\n",ans);
clear(n);
}
}

我的常数大,因为我太菜了

这种东西觉得想明白了收获还是挺大的,真正追求的不只是那个绿勾,还有题背后的东西

执.

模拟7 T3 寿司题解的更多相关文章

  1. 【2018.06.26NOIP模拟】T3节目parade 【支配树】*

    [2018.06.26NOIP模拟]T3节目parade 题目描述 学校一年一度的学生艺术节开始啦!在这次的艺术节上总共有 N 个节目,并且总共也有 N 个舞台供大家表演.其中第 i 个节目的表演时间 ...

  2. [NOIP10.4模拟赛]3.z题解--思维

    题目链接: 咕咕 闲扯: 哈哈这道T3考场上又敲了5个namespace,300+行,有了前车之鉴还对拍过,本以为子任务分稳了 结果只有30分哈哈,明明用极限数据对拍过不知怎么回事最后数据又是读不全, ...

  3. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  4. 【2018暑假集训模拟一】Day1题解

    T1准确率 [题目描述] 你是一个骁勇善战.日刷百题的OIer. 今天你已经在你OJ 上提交了y 次,其中x次是正确的,这时,你的准确率是x/y.然而,你最喜欢一个在[0; 1] 中的有理数p/q(是 ...

  5. 20180711模拟赛T3——聚变

    文件名: fusion 题目类型: 传统题 时间限制: 3秒 内存限制: 256MB 编译优化: 无 题目描述 知名科学家小A在2118年在计算机上实现了模拟聚变的过程. 我们将她研究的过程简化. 核 ...

  6. 20180520模拟赛T3——chess

    [问题描述] 小美很喜欢下象棋. 而且她特别喜欢象棋中的马. 她觉得马的跳跃方式很独特.(以日字格的方式跳跃) 小芳给了小美一张很大的棋盘,这个棋盘是一个无穷的笛卡尔坐标. 一开始\(time=0\) ...

  7. [NOIP10.6模拟赛]2.equation题解--DFS序+线段树

    题目链接: 咕 闲扯: 终于在集训中敲出正解(虽然与正解不完全相同),开心QAQ 首先比较巧,这题是\(Ebola\)出的一场模拟赛的一道题的树上强化版,当时还口胡出了那题的题解 然而考场上只得了86 ...

  8. 2019.6.20 校内测试 NOIP模拟 Day 1 分析+题解

    这次是zay神仙给我们出的NOIP模拟题,不得不说好难啊QwQ,又倒数了~ T1 大美江湖 这个题是一个简单的模拟题.   ----zay 唯一的坑点就是打怪的时候计算向上取整时,如果用ceil函数一 ...

  9. [CSP-S模拟测试50]反思+题解

    ??大部分人都觉得T3是道不可做题去刚T1T2了,于是我就侥幸苟到了前面? 这场考试比较成功的就是快速水掉了T1T2的部分分,1h拿到88分起码为之后硬肝T3上了保险(赛后发现就算T3爆零也能rank ...

随机推荐

  1. 多线程笔记-CancellationToken(取消令牌)

    介绍     为什么需要CancellationToken?因为Task没有方法支持在外部取消Task,只能通过一个公共变量存放线程的取消状态,在线程内部通过变量判断线程是否被取消,当Cancella ...

  2. 使用oss来存取及优化图片资源

    目录 1. 开通阿里云OSS,并创建存储空间 2. 图片上传及处理 2.1 图片上传 2.2 图片处理 前言: 在日常开发中,不免会遇到需要实现图片上传与展示的需求.比如一个文章发布系统,我们通常会开 ...

  3. GO系列-ini文件处理

    gopkg.in/ini.v1 配置加载 创建一个空的配置 cfg := ini.Empty() 直接加载存在的配置文件,如果文件不存在就会报错 cfg, err := ini.Load(" ...

  4. [005] - JavaSE面试题(五):String类

    第一期:Java面试 - 100题,梳理各大网站优秀面试题.大家可以跟着我一起来刷刷Java理论知识 [005] - JavaSE面试题(五):String类 第1问:String.StringBuf ...

  5. Leetcode2.两数相加——简洁易懂

    > 简洁易懂讲清原理,讲不清你来打我~ 输入两个链表,相同位置相加,进位给下一个位置,输出相加后的链表![在这里插入图片描述](https://img-blog.csdnimg.cn/f43b7 ...

  6. [SHOI2014]概率充电器 题解

    注意到本题的贡献是不带权的,所以期望其实就是每个点的概率之和. 本题正着做好像不是很好做,要考虑 \(P(A+B)=P(A)+P(B)-P(A)P(B)\) 的容斥(因为这是两个条件至少满足一个,所以 ...

  7. Mysql数据量较大时分页查询优化

    据表 collect ( id, title ,info ,vtype) 就这4个字段,其中 title 用定长,info 用text, id 是主键,vtype是int,vtype是索引. 最后co ...

  8. 研究java ResultSet结果集

    java的结果集,实现类D:\storage\respository\com\sinosoft\local\oracle\1.0\oracle-1.0.jar!\oracle\jdbc\driver\ ...

  9. Bootstrap 树形列表与右键菜单

    Bootstrap 树形列表与右键菜单 介绍两个Bootstrap的扩展 Bootstrap Tree View 树形列表 jQuery contextMenu 右键菜单 Demo采用CDN分发,直接 ...

  10. angular5采坑之旅

    开始尝试angular5,在此记录下踩过的坑以备查询 1.按照element-angular的文档引入后报错 is not part of the compilation output.解决方法--在 ...