模拟7 T3 寿司题解

题目要求可以转化成一个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 寿司题解的更多相关文章
- 【2018.06.26NOIP模拟】T3节目parade 【支配树】*
[2018.06.26NOIP模拟]T3节目parade 题目描述 学校一年一度的学生艺术节开始啦!在这次的艺术节上总共有 N 个节目,并且总共也有 N 个舞台供大家表演.其中第 i 个节目的表演时间 ...
- [NOIP10.4模拟赛]3.z题解--思维
题目链接: 咕咕 闲扯: 哈哈这道T3考场上又敲了5个namespace,300+行,有了前车之鉴还对拍过,本以为子任务分稳了 结果只有30分哈哈,明明用极限数据对拍过不知怎么回事最后数据又是读不全, ...
- contesthunter暑假NOIP模拟赛第一场题解
contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...
- 【2018暑假集训模拟一】Day1题解
T1准确率 [题目描述] 你是一个骁勇善战.日刷百题的OIer. 今天你已经在你OJ 上提交了y 次,其中x次是正确的,这时,你的准确率是x/y.然而,你最喜欢一个在[0; 1] 中的有理数p/q(是 ...
- 20180711模拟赛T3——聚变
文件名: fusion 题目类型: 传统题 时间限制: 3秒 内存限制: 256MB 编译优化: 无 题目描述 知名科学家小A在2118年在计算机上实现了模拟聚变的过程. 我们将她研究的过程简化. 核 ...
- 20180520模拟赛T3——chess
[问题描述] 小美很喜欢下象棋. 而且她特别喜欢象棋中的马. 她觉得马的跳跃方式很独特.(以日字格的方式跳跃) 小芳给了小美一张很大的棋盘,这个棋盘是一个无穷的笛卡尔坐标. 一开始\(time=0\) ...
- [NOIP10.6模拟赛]2.equation题解--DFS序+线段树
题目链接: 咕 闲扯: 终于在集训中敲出正解(虽然与正解不完全相同),开心QAQ 首先比较巧,这题是\(Ebola\)出的一场模拟赛的一道题的树上强化版,当时还口胡出了那题的题解 然而考场上只得了86 ...
- 2019.6.20 校内测试 NOIP模拟 Day 1 分析+题解
这次是zay神仙给我们出的NOIP模拟题,不得不说好难啊QwQ,又倒数了~ T1 大美江湖 这个题是一个简单的模拟题. ----zay 唯一的坑点就是打怪的时候计算向上取整时,如果用ceil函数一 ...
- [CSP-S模拟测试50]反思+题解
??大部分人都觉得T3是道不可做题去刚T1T2了,于是我就侥幸苟到了前面? 这场考试比较成功的就是快速水掉了T1T2的部分分,1h拿到88分起码为之后硬肝T3上了保险(赛后发现就算T3爆零也能rank ...
随机推荐
- C++ 11 多线程初探-std::memory_order
std::memory_order(可译为内存序,访存顺序) 动态内存模型可理解为存储一致性模型,主要是从行为(behavioral)方面来看多个线程对同一个对象同时(读写)操作时(concurren ...
- C语言:const详解
希望定义这样一种变量,它的值不能被改变,在整个作用域中都保持固定.例如,用一个变量来表示班级的最大人数,或者表示缓冲区的大小.为了满足这一要求,可以使用const关键字对变量加以限定:const in ...
- Tutorial_6 运行结果
1.buyer_favorites.txt 2.代码 package mapreduce; import java.io.IOException; import java.util.Iterator; ...
- 手写系列-实现一个铂金段位的 React
一.前言 本文基于 https://pomb.us/build-your-own-react/ 实现简单版 React. 本文学习思路来自 卡颂-b站-React源码,你在第几层. 模拟的版本为 Re ...
- @classmethod和@staticmethod修饰符
@classmethod和@staticmethod 一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法. 而使用@staticmethod或@classmethod,就可以不需要实例化,直 ...
- 每天五分钟Go - 数组
//数组的声明,默认为0值 var a1 [2]int fmt.Println(a1) //数组的长度 fmt.Println(len(a1)) //遍历数组 for i, v := range a1 ...
- SSM框架中,利用ajax,jQuery,json动态刷新局部页面,实现用户名查重提示
1.在applicationContext.xml配置json文件 2.jsp页面 3.js语句 js语句在script标签中使用, 4.控制层 5.逻辑处理层 6.Dao层方法 7.Mapping层 ...
- C++第四十一篇 -- 安装成功的第一个驱动文件
参考链接:https://blog.csdn.net/LEON1741/article/details/87291839 一.新建工程 二.写一个Driver.c #include <ntddk ...
- jvm源码解读--14 defNewGeneration.cpp gc标记复制之后,进行空间清理
进入Eden()->clean()函数 void EdenSpace::clear(bool mangle_space) { ContiguousSpace::clear(mangle_spac ...
- shiro反序列化550、721
shiro550反序列化 获取docker镜像 docker pull medicean/vulapps:s_shiro_1 重启docker systemctl restart docker 启动d ...