思考题(Sleep in Class,cf 733E)
来源:互联网 发布:糖果屋淘宝 编辑:程序博客网 时间:2024/06/07 11:32
仔细思考就能找到规律,那就是这些楼梯就像浪潮一样的把你往两边推。遇到反向的就被挡回来,但你只能挡我一次,之后你就变成了浪潮的一部分。n那么大既然不能模拟,那就只能计算啊。
比如说当前是'U',那么我就往上走,如果遇到‘U’,那就是我的助推器,我会一直向前走,并把沿途所有‘U’都变成‘D’。(所有助推器在使用过后都变成了反向的助推器)直到我遇到了‘D’,这个‘D’就会变成‘U’,然后我就被挡了回来(这堵墙把你挡了回来,但是它也被撞成了助推器)。被挡回来的我沿着之前制造的反向助推器一路返回,直到遇见新的墙,又被挡回来。。循环往复,更多的墙被撞成了助推器,移动范围越来越大,直到你掉下去QAQ
然后就是看哪边的墙少我就从哪边掉下去咯。那步数怎么计算呢。
遍历一下O(n^2)不行呀。
说明我们要保存一些东西,然后用更优质的算法算出答案。
我们从i开始,往两边跑,不断被弹回来,直到掉下去。
每次被弹回来肯定又经过初始位置,最后一次弹回来经过初始位子就一去不回了。
那么我们只要找到所有被弹回来的地方j,然后2*∑|i-j|+d。d是一去不回的长度。
如果我一开始在‘U’,那么我右边所有的‘D’以及我左边所有的‘U’都会是潜在的返回点。之所以说是潜在,是因为可能已经先掉下去了。
那么设右边有d个‘D’,左边有u个‘U’,我一开始往右走。
那么如果d<=u,我就会从右边出去,而且我分别撞了min(d,u)=d个‘U’和‘D’。他们都是离出发点最近的那d个。
否则就从左边出去。分别撞了min(d,u)=u个‘U’以及u+1个‘D’。他们也都是离出发点最近的那几个。
而且只考虑右边的‘D’和左边的‘U’。
一开始在‘D’的情况同理。
我们需要快速的求出这些返回点到初始点距离之和。
我们发现这些‘U’和‘D’都是连续的,那么就可以考虑用前缀和优化了。
cntu[i],cntd[i]分别代表前i个位子一共有多少个‘U’或‘D’。可以通过一遍扫描预处理出。有了它我们就可以O(1)算出任何连续区间内‘U’或‘D’的总个数。
sumu[i],sumd[i]分别代表前i个位子的所有‘U’或‘D’距离角标0的距离的和。也可以通过一遍扫描预处理出。有了它我们就可以O(1)算出任何连续区间内‘U’或‘D’距离角标0的距离的和。再配合cntu或cntd就可以O(1)算出任何连续区间内‘U’或‘D’距离任何角标的距离的和。
比如我想算区间[i,j]内所有‘U’距离角标k的距离的和。
那么当k<=i时,ansu(i,j,k)=(sumu[j]-sumu[i-1])-(cntu[j]-cntu[i-1])*k
当k>=j时,ansu(i,j,k)=(cntu[j]-cntu[i-1])*k-(sumu[j]-sumu[i-1])
否则,ansu(i,j,k)=ans(i,k,k)+ans(k+1,j,k)
然后如果初始点在k,是‘U’,最左边的返回点角标为x,最右边的返回点角标为y(掉下去就是正负无穷)答案不就是ansu(x,k-1,k)+ansd(k+1,y,k)+d吗。d是一去不回的长度。
那怎么求角标呢?对cntu或cntd用二分查找第几个即可。如果知道了初始位置以及左右两边分别有几个‘U’和‘D’,第几个就很容易算出。只不过一会要用lower_bound,一会要用upper_bound好麻烦,角标多一点少一点都不行,很容易出错。
然后遍历一遍位子,讨论一下带公式一算就好了。
代码
#include<bits/stdc++.h>#define maxn 1000010using namespace std;typedef long long ll;ll n;char str[maxn];ll cntu[maxn];ll cntd[maxn];ll sumu[maxn];ll sumd[maxn];ll CNTU;ll CNTD;int main(){ scanf("%I64d%s",&n,str+1); for(ll i=1;i<=n;i++) { cntu[i]=cntu[i-1]; cntd[i]=cntd[i-1]; sumu[i]=sumu[i-1]; sumd[i]=sumd[i-1]; if(str[i]=='U') { CNTU++; cntu[i]++; sumu[i]+=i; } else { CNTD++; cntd[i]++; sumd[i]+=i; } } for(ll i=1;i<=n;i++) if(str[i]=='U') { if(cntu[i-1]>=CNTD-cntd[i]) { ll k=upper_bound(cntu+1,cntu+n+1,cntu[i-1]-CNTD+cntd[i])-cntu; printf("%I64d ",(-(sumu[i-1]-sumu[k-1])+(sumd[n]-sumd[i]))*2+n-i+1); } else { ll k=lower_bound(cntd+1,cntd+n+1,cntd[i]+cntu[i-1]+1)-cntd; printf("%I64d ",(-sumu[i-1]+(sumd[k]-sumd[i])-i)*2+i); } } else { if(cntu[i-1]<=CNTD-cntd[i]) { ll k=lower_bound(cntd+i,cntd+n+1,cntd[i]+cntu[i-1])-cntd; printf("%I64d ",(-sumu[i-1]+(sumd[k]-sumd[i]))*2+i); } else { ll k=upper_bound(cntu+1,cntu+n+1,cntu[i-1]-CNTD+cntd[i]-1)-cntu; printf("%I64d ",(i-(sumu[i-1]-sumu[k-1])+(sumd[n]-sumd[i]))*2+n-i+1); } } return 0;}
- 思考题(Sleep in Class,cf 733E)
- CodeForces 733 E.Sleep in Class(队列)
- CodeForces 733E Sleep in Class
- CODEFORCES 733E Sleep in Class
- 【Codeforces 733E】 Sleep in Class 【模拟】
- Codeforces 733E Sleep in Class【思维】
- 【codeforces 733E】Sleep in Class 题解
- Codeforces Round #378 (Div. 2) E. Sleep in Class (思考,双指针,模拟)
- Codeforces Round #378 (Div. 2) E. Sleep in Class
- Codeforces Round #378 (Div. 2) E. Sleep in Class 思维 没弄很懂
- E. Mishap in Club (CF 245E)
- 【CF 550E】 Brackets in Implications(贪心)
- CF378E-Sleep in Class及378反思
- CF 550E Brackets in Implications
- CF 632E Thief in a Shop
- 【CF 702E】Analysis of Pathes in Functional Graph(倍增)
- cf-e
- CF 479E Riding in a Lift 前缀和 DP
- Ljava/lang/String;错误
- Android简单的加密解密处理
- [samtools]mpileup命令简介
- BIOS/UEFI基础——UEFI网络框架之支撑模块DPC
- MVC和MVVM以及MVP的介绍
- 思考题(Sleep in Class,cf 733E)
- java基础之-------重写
- 浅析抽象类与接口
- 免费网络存储
- Laravel-dingo/api获取路由
- java中匿名内部类的理解
- 第12周课后实践 多文件组织
- 2016-浙江理工新生赛-部分题解
- Git自动化部署