题目链接 https://www.luogu.com.cn/problem/P2882

分析

这个题来看的话好像有点难下手,不如再去读一遍题 N遍,发现一句话很重要Each time the machine is used, it reverses the facing direction of a contiguous group of K cows in the line,就是说只能翻转固定的长度区间,那这样是不是就可以枚举区间了?枚举一层区间,再枚举每次起点,最后加上区间修改,时间复杂度\(O(N^3)\),肯定会T掉,接下来就考虑优化了。

优化怎么入手呢?时间主要就是出在这三层循环上,只要省掉一层循环,时间复杂度就能到\(O(N^2)\),这样就可以过,第一层循环,显然不能省略,第二层同样,只有在区间修改这一层循环上可以做点手脚,回忆区间修改,有几种做法,线段树,树状数组,还有差分,前两者用在这都有点大材小用或是说不是很合适,因为判断是否区间修改完成不好判断,而差分用在这个区间上就很合适了。那我们大概思路也就有了,首先读入数组,将B标记成1,F标记成0,这里怎么标记都无所谓,然后利用枚举区间,差分修改,最后输出答案,下面考虑一下细节。

我们枚举区间完,要从左到右一次反转区间,为什么呢?题目中要求的是最小次数,就是要先保证次数最小,再考虑区间长度,而我们如果先修改后面的,把后面改好了,再去改前边的,结果一定不会比先改前边的好(有可能相等,如00100),所以我们为保证最小次数,一定从最左端开始依次枚举,如果这个点不符合,就把他后面的整个区间翻转,这里就要用到差分了,肯定直接修改会T掉,我们可以考虑,如果这个区间要修改,那么原来的1会变成2,0会变成1,好像没什么规律,但再看就发现所有的奇数都需要改变,偶数就不用,每次修改给整个区间加一,判断奇偶数就行,然后这就变成了一个区间加一个数的操作,相信大家应该都会。这样修改就完成了,那么怎么判断能不能完成题目的任务呢?由题意可以知道如果当前区间长度小于修改的区间长度,是不能修改的,也就是从n往前的长度为len的区间总是无法被修改的,所以判断这一段区间内有无不满足条件的点即可。

最后找答案的时候也有一个地方,就是当操作修改次数不同时,直接用操作修改次数最小的那个答案就行,但如果当前操作次数和原来答案相同,是不是要考虑一下区间长度改成最小值?答案显然是不是,…………,因为我们是从小到大枚举的区间长度,所以在遇到相等的时候,已经得到的答案的区间长一定是小的,所以只在次数不同时修改答案,但判断上也不会错。

其他优化

当然以下优化不加也没问题,毕竟算法时间复杂度足够过掉这道题。

我做完之后看了看时间大概700ms左右,好像有点高,看别人的时间好像没有特别大,所以我加了加小优化。



为方便说,由上到下一次标号\(1-4\),1,2跑的时间还是挺快的但没啥用,\(NOIp\)不可能给你开O2也不可能给你c++17,所以还是看一下3和4,这俩时间大概有一倍的关系,看一下代码吧

3

#include<cstdio>
#include<cstring>
using namespace std;
const int N=5e3+10;
char s[3];
int cf[N],a[N];
int min(int a,int b){
if(a<b)return a;
else return b;
}
int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s);
if(s[0]=='B')a[i]=1;
else a[i]=0;
}
int res=0x3f3f3f3f,ans=0x3f3f3f3f;
for(int len=1;len<=n;len++){
int cnt=1,k=0;memset(cf,0,sizeof(cf));
for(int i=1;i<=n;i++){
cf[i]+=cf[i-1];
if(i+len-1<=n){
if(a[i]+cf[i]&1){
cf[i]++;cf[i+len]--;k++;
}
}else if(cf[i]+a[i]&1){cnt=0;break;}
}
if(cnt)
if(k<ans){
ans=k;res=len;
}
else if(k==ans)res=min(res,len);
}
printf("%d %d",res,ans);
return 0;
}

4

#include<cstdio>
#include<cstring>
using namespace std;
const int N=5e3+10;
char s[3];
int cf[N],a[N];
int min(int a,int b){
if(a<b)return a;
else return b;
}
int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s);
if(s[0]=='B')a[i]=1;
else a[i]=0;
}
int res=0x3f3f3f3f,ans=0x3f3f3f3f;
for(int len=1;len<=n;len++){
int cnt=1,k=0;memset(cf,0,sizeof(cf));
for(int i=1;i<=n;i++){
cf[i]+=cf[i-1];
if(i+len-1<=n){
if(a[i]+cf[i]&1){
cf[i]++;cf[i+len]--;k++;
}
}else if(cf[i]+a[i]&1)cnt=0;
}
if(cnt)
if(k<ans){
ans=k;res=len;
}
else if(k==ans)res=min(res,len);
}
printf("%d %d",res,ans);
return 0;
}

其实就是少一个break,感觉这个加上还是很有必要的,因为可能极限数据的时候,CCF那评测机状态不好,再卡一下,可能会出问题。

问题

那么有没有可能最开始全部是朝前的呢?答案是没有,英文题面中已经讲到,有一些牛,所以说不可能其实全部朝前边的。

USACO07MAR Face The Right Way G 差分的更多相关文章

  1. [USACO07MAR]Face The Right Way G

    发现选定一个长度后,怎么翻转是固定的. 那我们直接选定一个长度去操作就行. 优化操作过程 类似于堆里打持久化标记一样的感觉. [USACO07MAR]Face The Right Way G // P ...

  2. 洛谷 P2882 [USACO07MAR]Face The Right Way G

    题目传送门 题目描述 Farmer John has arranged his N (1 ≤ N ≤ 5,000) cows in a row and many of them are facing ...

  3. luogu P2882 [USACO07MAR]Face The Right Way G

    题目描述 Farmer John has arranged his N (1 ≤ N ≤ 5,000) cows in a row and many of them are facing forwar ...

  4. BZOJ3453: tyvj 1858 XLkxc(拉格朗日插值)

    题意 题目链接 Sol 把式子拆开,就是求这个东西 \[\sum_{i = 0} ^n \sum_{j = 1}^{a + id} \sum_{x =1}^j x^k \pmod P\] 那么设\(f ...

  5. BZOJ4650:[NOI2016]优秀的拆分——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4650 https://www.luogu.org/problemnew/show/P1117 如果 ...

  6. 『题解』[NOI2016]优秀的拆分

    如果一个字符串可以被拆分为\(AABB\)的形式,其中$A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串\(aabaabaa\),如果令\(A=aab\),\(B=a\ ...

  7. CodeChef DGCD Dynamic GCD

    CodeChef题面 Time limit 210 ms Code length Limit //内存限制也不说一下,真是的-- 50000 B OS Linux Language limit C, ...

  8. Storyboards Tutorial 03

    这一节主要介绍segues,static table view cells 和 Add Player screen 以及 a game picker screen. Introducing Segue ...

  9. 文件图标SVG

    ​<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink ...

随机推荐

  1. c/s用户与服务器之间的传输

    ####第一页 <%@ page language="java" contentType="text/html; charset=UTF-8" pageE ...

  2. js获取当前日期是一年中的第几天

    js获取当前日期为一年中的第几天 const currentYear = new Date().getFullYear().toString(); // 今天减今年的第一天(xxxx年01月01日) ...

  3. 一个轻量级的基于 .NET Core 的 ORM 框架 HSQL

    HSQL 是一种轻量级的基于 .NET Core 的数据库对象关系映射「ORM」框架 HSQL 是一种可以使用非常简单且高效的方式进行数据库操作的一种框架,通过简单的语法,使数据库操作不再成为难事.目 ...

  4. SpringBoot1.5.10.RELEASE整合druid时,在druid monitor界面出现(*) property for user to setup

    接上篇随笔,配置druid之后出现的错误,解决方法如下: @Bean(destroyMethod = "close",initMethod = "init") ...

  5. php获取当前周的第一天与最后一天

    1 2 3 4 5 6 7 8 9 10 // 当前日期   $sdefaultDate = date("Y-m-d");   // $first =1 表示每周星期一为开始日期  ...

  6. eclipse代码提示完善

    转载请注明出处:https://www.cnblogs.com/Higurashi-kagome/p/12263267.html 1.参考https://blog.csdn.net/ithomer/a ...

  7. 解决 unable to lock the administration directory (/var/lib/dpkg/) 问题

    阿里开源镜像站提供了raspbian的软件包镜像,国内的用户可以选择改用阿里镜像站作为更新源. 但是在更换源之后,执行 sudo apt-get update && apt-get u ...

  8. JavaMail(一):利用JavaMail发送简单邮件

    JavaMail,提供给开发者处理电子邮件相关的编程接口.它是Sun发布的用来处理email的API.它可以方便地执行一些常用的邮件传输.但它并没有包含在JDK中,要使用JavaMail首先要下载ja ...

  9. 求你了,别再说Java对象都是在堆内存上分配空间的了!

    Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点,所以,即使是一个Java的初学者,也一定或多或少的对JVM有一些了解.可以说,关于JVM的相关知识,基本是每个Java开发者 ...

  10. go中处理各种请求方式以及处理接口请求参数

    话不多说直接上代码,解读内容全部在代码中 1.处理请求方式 package main import ( "fmt" "io/ioutil" "net/ ...