题目要求可以转化成一个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. buu [MRCTF2020]keyboard

    密文: ooo yyy ii w uuu ee uuuu yyy uuuu y w uuu i i rr w i i rr rrr uuuu rrr uuuu t ii uuuu i w u rrr ...

  2. 白话边缘计算解决方案 SuperEdge

    一.SuperEdge的定义 引用下SuperEdge开源官网的定义: SuperEdge is an open source container management system for edge ...

  3. 「AGC029C」Lexicographic constraints

    「AGC029C」Lexicographic constraints 传送门 好像这个题非常 easy. 首先这个答案显然具有可二分性,所以问题转化为如何判定给定的 \(k\) 是否可行. 如果 \( ...

  4. 刚刚进公司不会SVN 菜鸟感觉好蛋疼-----------SVN学习记

    这篇文章源于6月份给公司新人作的关于SVN使用的培训,转眼已经过了几个月的时间,丢了也怪可惜的,于是整理出来希望能够帮助后来人快速入门. 转载:https://blog.csdn.net/maplej ...

  5. 【Mysql】InnoDB 引擎中的数据页结构

    InnoDB 是 mysql 的默认引擎,也是我们最常用的,所以基于 InnoDB,学习页结构.而学习页结构,是为了更好的学习索引. 一.页的简介 页是 InnoDB 管理存储空间的基本单位,一个页的 ...

  6. MapReduce学习总结之Combiner、Partitioner、Jobhistory

    一.Combiner 在MapReduce编程模型中,在Mapper和Reducer之间有一个非常重要的组件,主要用于解决MR性能瓶颈问题 combiner其实属于优化方案,由于带宽限制,应该尽量ma ...

  7. 微信小程序云开发-云存储-上传文件(word/excel/ppt/pdf)到云存储

    说明 word/excel/ppt/pdf是从客户端会话选择文件.使用chooseMessageFile中选择文件. 一.wxml文件 上传按钮,绑定chooseFile <!--上传文件(wo ...

  8. 40.qt quick- 高仿微信实现局域网聊天V4版本(支持gif动图表情包、消息聊天、拖动缩放窗口)

    在上章37.qt quick- 高仿微信实现局域网聊天V3版本(添加登录界面.UDP校验登录.皮肤更换.3D旋转),我们已经实现了: 添加登录界面. UDP校验登录. 皮肤更换. 3D旋转(主界面和登 ...

  9. JDBC连接流程

    ConectionFactory cf = new ConectionFactory();//创建数据库连接Connection con = cf.getConection();//打开水数据库的连接 ...

  10. 斐波那契数列——Python实现

      # 功能:求斐波那契数列第 n 个数的值 # 在此设置 n n = 30 print('\n');print('n = ',n) # 代码生成 Fibonacci 序列,存于数组A A = [0] ...