• P2629 好消息,坏消息


    描述:https://www.luogu.com.cn/problem/P2629

    uim在公司里面当秘书,现在有n条消息要告知老板。每条消息有一个好坏度,这会影响老板的心情。告知完一条消息后,老板的心情等于之前老板的心情加上这条消息的好坏度。最开始老板的心情是0,一旦老板心情到了0以下就会勃然大怒,炒了uim的鱿鱼。

    uim为了不被炒,知道了了这些消息(已经按时间的发生顺序进行了排列)的好坏度,希望研究如何不让老板发怒。

    uim必须按照时间的发生顺序逐条将消息告知给老板。不过uim可以使用一种叫“倒叙”的手法,例如有n条消息,小a可以从k,k+1,k+2...n,1,2...k-1这种顺序通报。

    他希望知道,有多少个k,从k开始通报到n然后从1通报到k-1可以让老板不发怒。


    又是比较难想的一题,虽然这已经是第二次做了........

    首先区间牵涉到k~n,n~1,那么大概率是要断环为链的。

    断环为链后,题目要求就变为了:对于每一个合法的k,都要满足k--(n+k-1)中,到任意一点的和都是非负的。熟悉前缀和的人应该知道,如果用 s [ i ] 表示1--i的所有数的和,那么s [ j ] - s [ i-1 ] 就是i--j所有数的和。所以用前缀和预处理后,s [ i ] - s [ k-1 ] 就是k--i (k<=i<=n+k-1)的和了,我们只要判断这个和是否为负即可。

    既然这么说,那么是否要判断k--n+k-1中每一个数的和呢?当然不是,因为其中如果只要有一点的和是负的,那么这个k就是不合法的了,所以我们只需要判断一次——判断最小的si减去s[k-1]是否为负

    接下来就是单调队列的事了。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll n,p[2000009],q[2000009];
    ll a[2000009],sumn[2000009],he[2000009];
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)    scanf("%lld",&a[i]),sumn[i]=sumn[i-1]+a[i];
        for(int i=n+1;i<=n+n;i++)    a[i]=a[i-n],sumn[i]=sumn[i-1]+a[i];
        int tail=0,head=1,l=n-1;
        for(int i=1;i<=n+n;i++)
        {
            while(tail>=head&&q[tail]>=sumn[i])    tail--;
            q[++tail]=sumn[i],p[tail]=i;
            while(p[head]+l<=i)    head++;
            if(i>=n)
                he[i-l]=q[head];//区间长度为n-1,所以从n开始记录 
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            if(he[i]-sumn[i]>=0)    ans++;
        cout<<ans;
    }
  • 相关阅读:
    Oracle SQL语句记录
    Gvim 在进行文件对比时报cannot read or write temp files
    Java Lock
    Java Synchronized
    CLH锁 、MCS锁
    JVM 运行时内存结构
    XSS攻击及防御
    Java IO 技术之基本流类
    Java 对象的串行化(Serialization)
    Java final关键字
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12532699.html
Copyright © 2020-2023  润新知