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/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    分布式机器学习:算法、理论与实践——【1】
    LLVM Cookbook
    【前端】Webpack 进阶
    Noip2015 运输计划 树上差分 二分答案
    bzoj 2259: [Oibh]新型计算机 最短路 建模
    888E
    [ZJOI2012]旅游 对偶图 树的直径
    [HAOI2007]理想的正方形 单调队列 暴力
    bzoj1457: 棋盘游戏 SG函数 Nim
    Bomb HDU
  • 原文地址:https://www.cnblogs.com/sunjianzhao/p/13455766.html
Copyright © 2011-2022 走看看