思考题(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;}


0 0
原创粉丝点击