[JZOJ4788] 【NOIP2016提高A组模拟9.17】序列
题目
描述
题目大意
一个序列,每次可以使一段区间内的所有数加一(模四)。
问最少的操作次数。
思考历程
一看这题目,诶,这不就是那道叫密码锁的题目吗?
然后随便打一打,样例过了,就再也没有思考这一题。
正解
其实我的想法完全错了。
因为这题只能加,不能减啊!
于是就得考虑另一个方法。
题目可以转成这样的问题:给你一个数列,你可以预先给其中的数加四,然后每次对一个区间进行减一操作,问最少的操作数。
显然,如果已经加四了,就是一道大水题(好像叫……粉刷栅栏)?
我们先不考虑加四,那么答案就是∑max(ai−ai−1,0)\sum{max(a_i-a_{i-1},0)}∑max(ai−ai−1,0)
然后我们考虑加四会有什么影响。
现在我们考虑一下,假设有两个高地为lll和rrr,中间的比较低,要把它们降下来,能不能通过抬高中间的,使得操作数尽量小呢?
然后开始按照lll和l+1l+1l+1之差和r−1r-1r−1和rrr之差分类讨论。
接着就可以发现,只有(−3,3)(-3,3)(−3,3)(−2,3)(-2,3)(−2,3)(−3,2)(-3,2)(−3,2)的情况是有意义的。
于是我们扫一扫有没有这样的东西,减去它们的贡献就好了。
要注意,如果一起做,有可能搞完了(−2,3)(-2,3)(−2,3),就没办法搞(−3,3)(-3,3)(−3,3)了。
由于(−3,3)(-3,3)(−3,3)更优,所以先从左到右将它给搞掉。
接着重新搞剩下两种。
然后就可以做出来了,说实在的,这方法让我醉了……
还有一种比较强大的做法,没有分类讨论。
刚开始的操作是一样的,同样是计算出一个暂时的答案。
然后从前往后扫,如果现在走的是下坡路,就将高度差ai−ai−1+4a_i-a_{i-1}+4ai−ai−1+4存入一个桶中。
如果在走上坡路,记高度差为xxx,就在桶种找小于xxx的第一个有值的,记为jjj。
如果找到了就让答案减去x−jx-jx−j,然后xxx在桶中的值减一,jjj在桶中的值加一。
这样就可以计算出答案了。
具体原因什么的……感觉上有些玄学,我是感性理解的。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
int n;
int a[N],c[N];
int las[N];
int main(){
int T;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
for (int i=1;i<=n;++i){
int x;
scanf("%d",&x);
a[i]=(x-a[i]+4)%4;
}
int ans=0;
for (int i=0;i<=n;++i){
ans+=max(a[i+1]-a[i],0);
c[i]=a[i+1]-a[i];
}
memset(las,255,sizeof las);
int cnt2=0,cnt3=0;
for (int i=0,j=-1;i<=n;++i)
if (c[i]==-3){
cnt3++;
las[i]=j;
j=i;
}
else if (c[i]==3 && cnt3){
cnt3--;
c[j]=c[i]=0;
j=las[j];
ans-=2;
}
cnt3=0;
for (int i=0;i<=n;++i)
if (c[i]==-2)
cnt2++;
else if (c[i]==-3)
cnt3++;
else if (c[i]==2 && cnt3)
cnt3--,ans--;
else if (c[i]==3 && cnt2)
cnt2--,ans--;
printf("%d\n",ans);
}
return 0;
}
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
int n;
int a[N];
int buc[4];
int main(){
int T;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
for (int i=1;i<=n;++i){
int x;
scanf("%d",&x);
a[i]=(x-a[i]+4)%4;
}
int ans=0;
for (int i=1;i<=n;++i)
ans+=max(a[i]-a[i-1],0);
memset(buc,0,sizeof buc);
for (int i=1;i<=n;++i)
if (a[i-1]>a[i])
buc[a[i]-a[i-1]+4]++;
else{
int j=0;
for (;j<a[i]-a[i-1];++j)
if (buc[j])
break;
if (buc[j]){
buc[j]--,buc[a[i]-a[i-1]]++;
ans-=a[i]-a[i-1]-j;
}
}
printf("%d\n",ans);
}
return 0;
}
总结
分类讨论是一种很恶心的方法……
另一种说法叫做:面向数据编程
[JZOJ4788] 【NOIP2016提高A组模拟9.17】序列的更多相关文章
- 【JZOJ4788】【NOIP2016提高A组模拟9.17】序列
题目描述 输入 输出 样例输入 1 5 2 1 3 0 3 2 2 0 1 0 样例输出 1 数据范围 解法 考虑没有模的情况,问题就仅仅只是简单的差分问题(广告铺设): 设r[i]是第i位需要加的次 ...
- 【JZOJ4787】【NOIP2016提高A组模拟9.17】数格子
题目描述 输入 输出 样例输入 1 10000 3 10000 5 10000 0 0 样例输出 1 11 95 数据范围 每个测试点数据组数不超过10组 解法 状态压缩动态规划. 设f[i][j]表 ...
- 【NOIP2016提高A组模拟9.17】序列
题目 分析 首先用\(a_i\)表示达到目标的步数\(B_i-A_i(mod 4)\) 根据粉刷栅栏,先不管mod 4的情况,答案就是\(\sum\max(a_i-a_{i+1},0)\) 那我们刚才 ...
- NOIP2016提高A组模拟9.17总结
第一题,典型的隔板问题, 但是我忘记隔板问题怎么打,一开始在花了1小时,还是没想出来,果断弃疗, 最后的40分钟,我打完了第二题,接着又用了20分钟推敲出一种极其猥琐的式子来代替,可惜预处理的阶乘忘记 ...
- 【NOIP2016提高A组模拟9.17】数格子
题目 分析 设表示每一行的状态,用一个4位的二进制来表示,当前这一行中的每一个位数对下一位有没有影响. 设\(f_{i,s}\)表示,做完了的i行,其状态为s,的方案数. 两个状态之间是否可以转移就留 ...
- 【NOIP2016提高A组模拟9.17】小a的强迫症
题目 分析 题目要求第i种颜色的最后一个珠子要在第i+1种颜色的最后一个珠子之前, 那么我们从小到大枚举做到第i种,把第i种的最后一颗珠子取出,将剩下的\(num(i)-1\)个珠子插入已排好的前i- ...
- 【NOIP2016提高A组模拟8.17】(雅礼联考day1)总结
考的还ok,暴力分很多,但有点意外的错误. 第一题找规律的题目,推了好久.100分 第二题dp,没想到. 第三题树状数组.比赛上打了个分段,准备拿60分,因为时间不够,没有对拍,其中有分段的20分莫名 ...
- 【NOIP2016提高A组模拟8.17】(雅礼联考day1)Binary
题目 分析 首先每个数对\(2^i\)取模.也就是把每个数的第i位以后删去. 把它们放进树状数组里面. 那么当查询操作, 答案就位于区间\([2^i-x,2^{i-1}-1-x]\)中,直接查询就可以 ...
- 【NOIP2016提高A组模拟8.17】(雅礼联考day1)Value
题目 分析 易证,最优的答案一定是按\(w_i\)从小到大放. 我们考虑dp, 先将w从小到大排个序,再设\(f_{i,j}\)表示当前做到第i个物品,已选择了j个物品的最大值.转移就是\[f_{i, ...
随机推荐
- 6 Accessing and Managing Symbols with armlink
6.4 Image$$ execution region symbols The linker generates Image$$ symbols for every execution region ...
- 浅析AIDL的使用和工作原理
AIDL是一种接口定义语言,用于生成可在Android设备上两个进程之间进行进程间通信(IPC)的代码. AIDL的使用 新建一个aidl文件,定义进程间通信的接口 // IStudentManage ...
- Poi设置列样式
最近做的项目中用到Poi导出Excel文件做模板,其中有的列需要设置为文本格式,查资料发现都是给单元格设置样式,由于是模板单元格都没内容,所以不能通过设置单元格式样式的方式操作,网上有说法是不能设置列 ...
- neo4j采坑记
1.安装后启动不起来,解决方案: https://stackoverflow.com/questions/38607283/failed-to-start-neo4j-service 2.一直启动不 ...
- ELK日志分析系统(原创)
一.简介 ELK由Elasticsearch.Logstash和Kibana三部分组件组成: Elasticsearch是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引 ...
- 2018-8-10-使用-IncrediBuild-提升-VisualStudio-编译速度
title author date CreateTime categories 使用 IncrediBuild 提升 VisualStudio 编译速度 lindexi 2018-08-10 19:1 ...
- ExecutorService线程池submit的使用
有关线程池ExecutorService,只谈submit的使用 可创建的类型如下: private static ExecutorService pool = Executors.newFixedT ...
- js 本地预览图片和得到图片实际大小
//填充预览图片 function adpter(file, upfile) { var imgName = new Date().getTime() + file.name.substr(file. ...
- du和df
du,disk usage,是通过搜索文件来计算每个文件的大小然后累加,du能看到的文件只是一些当前存在 的,没有被删除的.(-s:summarize 仅显示总计,只列出最后加总的值) df,disk ...
- Perl 环境安装
Perl 环境安装 在我们开始学习 Perl 语言前,我们需要先安装 Perl 的执行环境. Perl 可以在以下平台下运行: Unix (Solaris, Linux, FreeBSD, AIX, ...
