博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P3564 [POI2014]BAR-Salad Bar
阅读量:6819 次
发布时间:2019-06-26

本文共 2136 字,大约阅读时间需要 7 分钟。

我是来帮加藤大佬写题解的……全世界都没找到加藤大佬写法的说明……很难受……

首先我们把\(p\)看成\(1\)\(j\)看成\(-1\),一个区间满足条件就意味着这个区间的所有前缀和都大于等于\(0\),所有后缀和都大于等于\(0\)

我们记录一下前缀和,所有前缀和大于等于\(0\)就是\(sum[i]-sum[l-1]\geq 0\),所有后缀和都大于等于\(0\)就意味着\(sum[n]-sum[i-1]\geq sum[n]-sum[r]\),即\(sum[i-1]\leq sum[r]\),然后因为\(sum[r]\geq sum[l-1]\)已经在第一个条件里满足了,所以合起来就是\(sum[i]\geq sum[l-1]\)\(sum[r]\geq sum[i]\)。用人话说,一个区间满足条件,那么这个区间内的\(sum\)都不小于\(sum[l-1]\)\(sum[r]\)是这个区间中最大的数

于是我们定义\(to[i]\),意思是\([i,to[i]]\)中的所有数都大于等于\(sum[i]\),且\(sum[to[i]]\)为这个区间中最大的数,\(to[i]\)为所有满足条件的数中最靠右的。那么我们就可以枚举左端点\(i\),如果\(s[i]==j\)这个左端点肯定不行,否则这个左端点能匹配的最大的右端点就是\(to[i-1]\)

现在的问题就是怎么求出\(to[i]\)了,我们一开始先把所有的\(to[i]\)都赋值为\(i\),这样到时候可以少讨论一些边界情况。

首先,如果\(sum[i+1]<sum[i]\),即\(s[i+1]\)\(p\),那么\(to[i]\)只能等于\(i\),因为它的下一个就小于它了。所以我们只考虑讨论\(s[i+1]\)\(j\)的情况

我们考虑从后往前做,定义\(nxt[i]\)为它后面的第一个与它\(sum\)相等的位置,记录一个指针\(las\),表示每一次的\(to[i]\),现在做到了\(i\),那么\(las\)应该是指在\(to[i+1]\)的位置。

那么转移会有两种情况

1.\(to[i]=to[i+1]\),那么直接转移即可
5beecffa819e5.png
2.\(to[i]\)变大。比如图中,\(k\)的位置才是\(to[i]\)
5beed07a0d603.png
我们发现,在本题中,相邻两个数的值最多只会相差\(1\),于是若是存在如图\(2\)的情况,那么必然存在\(nxt[i]\)。不难证明\([i+1,nxt[i]-1]\)区间内的数肯定同时大于\(sum[i]\)或同时小于\(sum[i]\),如果全都小于那么有\(sum[i+1]<sum[i]\),我们之前已经处理掉了。所以\([i+1,nxt[i]-1]\)之间的数必然全都大于\(sum[i]\)。因为\(to[nxt[i]]\)已经求出来了,如果\(sum[to[nxt[i]]]\geq sum[las]\),我们可以把\([i,nxt[i]-1]\)这一段给接上去,那么新的区间\([i,to[nxt[i]]]\)肯定还是满足条件的,且不难证明不存在比它更优的。这种情况下我们让\(las\)指向\(to[nxt[i]]\)并更新\(to[i]\)即可。

只要处理出\([0,n-1]\)的所有的\(to[i]\)就可以了,最后的答案就是\(max\{to[i-1]-i+1\}(s[i]==p)\),时间复杂度\(O(n)\)

// luogu-judger-enable-o2//minamoto#include
using namespace std;const int N=1e6+10;int n,sum[N],head[N],nxt[N],to[N],mn;char s[N];int main(){// freopen("testdata.in","r",stdin); memset(head,-1,sizeof(head)); scanf("%d%s",&n,s+1); for(int i=1;i<=n;++i)sum[i]=sum[i-1]+(s[i]=='p'?1:-1),mn=min(mn,sum[i]); for(int i=n;~i;--i) nxt[i]=head[sum[i]-mn],head[sum[i]-mn]=i,to[i]=i; int ans=0; for(int i=n,las=n;i;--i){ if(s[i]=='j')las=i-1; else{ if(nxt[i-1]>=0&&sum[to[nxt[i-1]]]>=sum[las])las=to[nxt[i-1]]; to[i-1]=las,ans=max(ans,las-i+1); } } printf("%d\n",ans);return 0;}

转载于:https://www.cnblogs.com/bztMinamoto/p/9972054.html

你可能感兴趣的文章
并发编程之线程
查看>>
python开发部署时新增数据库中表的方法
查看>>
参加2018之江杯全球人工智能大赛 :视频识别&问答(四)
查看>>
阿里云跨地域访问私网
查看>>
通过angularJS官方案例快速入门
查看>>
Introduction of OpenCascade Foundation Classes
查看>>
Surface Normal Vector in OpenCascade
查看>>
Educational Codeforces Round 38 (Rated for Div. 2)
查看>>
内部类初识
查看>>
【python3的学习之路一】输入和输出
查看>>
在Eclipse中生成接口的JUnit测试类
查看>>
Oracle SQL常用内置系统函数总结
查看>>
[POJ] #1005# I Think I Need a Houseboat : 浮点数运算
查看>>
西湖论剑WP
查看>>
数组Array,集合List与字符串String,整形int的get类方法。
查看>>
【转】浏览器内核
查看>>
面试题:查找旋转数组中的某一元素
查看>>
uva12298(生成函数)
查看>>
C++ variable_template
查看>>
第十七章、程序管理与 SELinux 初探 工作管理 (job control)
查看>>