[jzoj]3499. 【NOIP2013模拟联考15】人类基因组(genes) (单调队列、前缀和、线段树解一题)
来源:互联网 发布:网络培训管理系统 编辑:程序博客网 时间:2024/05/17 08:51
Link
https://jzoj.net/senior/#contest/show/1947/0
Problem
给定一个序列
Data constraint
对于30%的数据,满足
对于50%的数据,满足
对于100%的数据,满足
Solution
Method-1
我们把序列复制一遍,对应的
那么继而求其前缀和,我们发现,每次枚举一个点
那么只需求出
即满足
显然可用线段树或树状数组或优先队列来维护.
Method-2
我们维护一个单调队列.
找出当前所有前缀和的最小值,并从最小值往右取次小值,次次小值……
即设
保证
每次枚举一个截取点
对于当前最小值
我们设一个可以继续“使用”的最小值为
如果
对应的前缀和的意思实际上是为每次被扔到末尾的数做准备的.
Code-2
var a,sum,d,b,c:array[0..2000000] of longint; n,i,j,ans,t:longint;begin assign(input,'genes.in'); reset(input); assign(output,'genes.out'); rewrite(output); readln(n); fillchar(d,sizeof(d),$7f); d[0]:=1; //序列长度 for i:=1 to n do begin read(a[i]); sum[i]:=sum[i-1]+a[i]; //前缀和 while (sum[i]<d[d[0]]) and (d[0]>0) do dec(d[0]); inc(d[0]); d[d[0]]:=sum[i]; //记录最小值,及从最小值往后的次小值,从次小值往后的次次小值…… b[d[0]]:=i; //记录对应下标 c[d[0]]:=0; //记录对应的前缀和,只要没被扔到末尾的数,对应前缀和为0. end; j:=1; for i:=1 to n do begin while (b[j]<i) and (j<=d[0]) do inc(j); if d[j]-sum[i-1]+sum[c[j]]>=0 then inc(ans); t:=sum[n]; while (t<d[d[0]]-sum[i]+sum[c[d[0]]]) and (d[0]>0) do dec(d[0]); inc(d[0]); d[d[0]]:=t; b[d[0]]:=i+n; c[d[0]]:=i; end; writeln(ans); close(input); close(output);end.
Method-3
但其实对于
我们把
那么每次我们就可以通过一个单调队列来判断新增的值的打小了,不需要再记录那么多的数.
Code-3
uses math;var a,sum:array[0..2000000] of longint; d:array[0..5000000] of longint; n,i,ans,l,r:longint;begin assign(input,'genes.in'); reset(input); assign(output,'genes.out'); rewrite(output); readln(n); for i:=1 to n do begin read(a[i]); a[i+n]:=a[i]; end; for i:=1 to n*2 do sum[i]:=sum[i-1]+a[i]; for i:=1 to n-1 do begin while (r>0) and (sum[i]<sum[d[r]]) do dec(r); inc(r); d[r]:=i; end; l:=1; for i:=1 to n do begin while (r>l) and (sum[i+n-1]<sum[d[r]]) do dec(r); inc(r); d[r]:=i+n-1; while (r>l) and (i>d[l]) do inc(l); if sum[d[l]]-sum[i-1]>=0 then inc(ans); end; writeln(ans); close(input); close(output);end.
Method-4
不用单调队列.
先求出前缀和,设为
设
设
那么每次,枚举一个断点
其实这与
Code-4
var f,g,s:array[0..1200000]of longint; n,i,ans,x:longint;begin assign(input,'genes.in'); reset(input); assign(output,'genes.out'); rewrite(output); readln(n); for i:=1 to n do begin read(x); s[i]:=s[i-1]+x; end; f[1]:=1; for i:=2 to n do if s[i]<s[f[i-1]] then f[i]:=i else f[i]:=f[i-1]; g[n]:=n; for i:=n-1 downto 1do if s[i]<s[g[i+1]] then g[i]:=i else g[i]:=g[i+1]; if s[f[n]]>=0 then ans:=ans+1; for i:=2 to n do if (s[f[i-1]]+s[n]-s[i-1]>=0) and (s[g[i]]-s[i-1]>=0) then ans:=ans+1; //前一个判断条件是判断被调走的,即[1..i-1]中新产生的前缀和的值,后一个条件则是继续判断没被调走中的最小前缀和值. writeln(ans); close(input);close(output);end.
- [jzoj]3499. 【NOIP2013模拟联考15】人类基因组(genes) (单调队列、前缀和、线段树解一题)
- 【NOIP2013模拟联考15】人类基因组(genes)
- [jzoj]3480. 【NOIP2013模拟联考9】阿Q的停车场(park)(线段树+堆)
- 【NOIP2013模拟联考13】线段
- [jzoj]3498. 【NOIP2013模拟联考14】图形变换(transform) (计算几何+矩阵乘法)
- [jzoj]3468. 【NOIP2013模拟联考7】OSU!(osu) (期望DP)
- [jzoj]3472. 【NOIP2013模拟联考8】匹配(match)(AC自动机+DP)
- [jzoj]3486. 【NOIP2013模拟联考10】道路改建(rebuild)(缩环+Tarjan+拓扑+bitset记录状态)
- JZOJ 3498【NOIP2013模拟联考14】图形变换
- JZOJ 3447【NOIP2013模拟联考2】摘取作物
- jzoj. 3450. 【NOIP2013模拟联考3】山峰(summits)
- JZOJ 3468. 【NOIP2013模拟联考7】OSU!(osu)
- [jzoj]3479. 【NOIP2013模拟联考9】工作安排(work)
- 【JZOJ 3492】【NOIP2013模拟联考12】数数(count)
- SSL2864 【NOIP2013模拟联考15】物语(spfa优化)
- JZOJ3501. 【NOIP2013模拟联考15】消息传递
- Feel Good (前缀和+单调队列)
- 3494. 【NOIP2013模拟联考13】线段(segment) (2017.9B组)
- shell 脚本执行dailybuild
- Linux上安装Redis(Ubuntu16.04+Redis3.2.8)最烦网上流传的那些根本走不通的教程
- 欢迎使用CSDN-markdown编辑器
- sqlalchemy中文问题解决方案
- Android 获取 View 宽高的常用正确方式,避免为零
- [jzoj]3499. 【NOIP2013模拟联考15】人类基因组(genes) (单调队列、前缀和、线段树解一题)
- html和native使用JSBridge交互
- 清除域名缓存
- Tomcat多域名配置
- 机器学习实战之kNN
- AS快捷键
- Java中二进制、八进制、十六进制变量的声明以及与十进制的互转
- java.util.Stack
- 以太坊client的transaction处理