zoukankan      html  css  js  c++  java
  • 洛谷P2629好消息坏消息(单调队列+前缀和)

    题目地址:https://www.luogu.com.cn/problem/P2629

    题意:有n个消息,每个消息有一个权值,这n个消息本身就有一个自己的排序(按照输入给出的顺序)1....n,现在你需要读取这n个消息,你一共有n种读取的顺序。k k+1 k+2....n 1 2 .. k-1.现在需要满足的是,你的这种方法的任意前i个数之和不小于0.问满足这样的读取顺序有多少种。

    输入:第一行n。第二行n个整数,分别表示每个消息的权值

    输出:满足条件的方案数目

    题解:首先观察有n种读取方式,那么便可以将这n个消息看成是一个环形排列,从中任意一个点切开就是一种读取方式。而在数据结构中,可以使用双倍空间表示这种存储方式,即1 2 3...n 1 2 3 .. n那么只需要从中选取连续的n个数就是一种读取方式。那么现在需要解决的问题就是选择的这种读取方式是否满足条件。例如选取的是第i个数到第i+n-1个数,那么只需要这n个数中的前缀的最小值pre[j]大于等于pre[i-1]即可。对于这种方式的区间最小值,便可以使用单调队列来实现,也就是使用双端队列就可以了。

    AC代码

    #include<iostream>
    #include<deque>
    using namespace std;
    const int N=1e6+5;
    int a[2*N],pre[2*N];
    int main(){
        int n;cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            a[i+n]=a[i];
        }
        pre[0]=0;
        for(int i=1;i<=n*2;i++){
            pre[i]=pre[i-1]+a[i];
        } 
        int ans=0;
        deque<int>de;
        for(int i=1;i<=n;i++){
            while(!de.empty()&&pre[i]<=pre[*(de.end()-1)]) de.pop_back();
            de.push_back(i);
        } 
        for(int i=n+1;i<=2*n;i++){
            while(!de.empty()&&*de.begin()<i-n+1) de.pop_front();
            while(!de.empty()&&pre[i]<=pre[*(de.end()-1)]) de.pop_back();
            de.push_back(i);
            if(pre[*de.begin()]>=pre[i-n]) ans++;
        }
        cout<<ans;
        return 0;
    }

    写于2020/8/7 22:57


    作者:孙建钊
    出处:http://www.cnblogs.com/sunjianzhao/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    php命令注入
    mysql事物
    安装php环境
    移除服务器缓存实例
    show user profile synchronization tools
    manual start user profile import
    JSON is undefined. Infopath Form People Picker in SharePoint 2013
    asp.net web 应用站点支持域账户登录
    Load sharepoint envirement by powershell
    sharepoint 2016 download
  • 原文地址:https://www.cnblogs.com/sunjianzhao/p/13455766.html
Copyright © 2011-2022 走看看