zoukankan      html  css  js  c++  java
  • COJ 2004 序列

    传送门:http://oj.cnuschool.org.cn/oj/home/addSolution.htm?problemID=978

    试题描述:

    WZJ的数字游戏又开始了。他写了N个自然数Ai到黑板上,让你选取一个起点L和一个终点R使sum(L,R)*min(L,R)最大,请你输出这个最大值。

    sum(L,R)表示AL一直加到AR之和,min(L,R)表示AL到AR的最小值。

    输入:

    第一行为一个正整数N。
    接下来为N个自然数Ai。

    输出:

    输出最大值。

    输入示例:

    7
    1 5 2 0 5 5 7

    输出示例:

    85

    其他说明:

    1<=N<=100000
    0<=Ai<=1000000

    题解:

    思路1:枚举所有的最小值,用单调栈或二分RMQ维护一下往前到哪里往后到哪里,然后乱搞答案。

    单调栈32ms最快:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 inline void read(int& x)
     7 {
     8     x = 0;
     9     int sig = 1;
    10     char ch = getchar();
    11     while(!isdigit(ch))
    12     {
    13           if(ch == '-') sig = -1;
    14         ch = getchar();
    15     }
    16     while(isdigit(ch))
    17     {
    18         x = x * 10 + ch - '0';
    19         ch = getchar();
    20     }
    21     x *= sig;
    22     return ;
    23 }
    24 
    25 const int maxn = 100000 + 10;
    26 
    27 int A[maxn];
    28 int L[maxn], R[maxn];
    29 
    30 int S[maxn];
    31 
    32 long long v[maxn], ans;
    33 
    34 int main()
    35 {
    36     int n;
    37     read(n);
    38     
    39     int top = 0;
    40     
    41     for(int i = 1; i <= n; i++)
    42     {
    43         read(A[i]);
    44         v[i] = v[i - 1] + A[i];
    45     }
    46     
    47     A[0] = A[n + 1] = -1;
    48     S[++top] = 0;
    49     
    50     for(int i = 1; i <= n; i++)
    51     {
    52         while(A[S[top]] >= A[i]) top--;
    53         L[i] = S[top] + 1;
    54         S[++top] = i;
    55     }
    56     
    57     S[top = 1] = n + 1;
    58     
    59     for(int i = n;i ; i--)
    60     {
    61         while(A[S[top]] >= A[i]) top--;
    62         R[i] = S[top] - 1;
    63         S[++top] = i;
    64         
    65         ans = max(ans, A[i] * (v[R[i]] - v[L[i] - 1]));
    66     }
    67     
    68     printf("%lld", ans);
    69     
    70     return 0;
    71 }

    由于每一个元素只进入单调栈一次,所以是o(n)的。

    RMQ157ms最慢:

     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 
     5 const int maxn = 100000 + 10;
     6 
     7 int A[maxn];
     8 
     9 int n;
    10 
    11 int log[maxn], d[maxn][20];
    12 
    13 long long ans, S[maxn];
    14 
    15 int f1[maxn], f2[maxn];
    16 
    17 void RMQ_init()
    18 {
    19     log[0] = -1;                   //你大爷 
    20     for(int i = 1; i <= n; i++) 
    21     {
    22         d[i][0] = A[i];
    23         log[i] = log[i >> 1] + 1;
    24     }
    25     
    26     for(int j = 1; (1 << j) <= n; j++)
    27       for(int i = 1; i + (1 << j) - 1 <= n; i++)   //你大爷 
    28         d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
    29         
    30     return ;
    31 }
    32 
    33 int query(int L, int R)
    34 {
    35     int k = log[R - L + 1];
    36     return min(d[L][k], d[R - (1 << k) + 1][k]);
    37 }
    38 
    39 int main()
    40 {
    41     int m, L, R, M;
    42     scanf("%d", &n);
    43     
    44     for(int i = 1; i <= n; i++)
    45     {
    46         scanf("%d", &A[i]);
    47         S[i] = S[i - 1] + A[i];
    48     }
    49       
    50     RMQ_init();
    51     
    52     for(int i = 1; i <= n; i++)
    53     {
    54         L = 1;
    55         R = i;
    56         
    57         while(L < R)
    58         {
    59             M = L + R >> 1;
    60             if(query(M, i) == A[i]) R = M;
    61             else L = M + 1; 
    62         }
    63         
    64         f1[i] = L;
    65     }
    66     
    67     for(int i = 1; i <= n; i++)
    68     {
    69         L = i;
    70         R = n + 1;
    71         
    72         while(L + 1 < R)
    73         {
    74             M = L + R >> 1;
    75             if(query(i, M) == A[i]) L = M;
    76             else R = M;
    77         }
    78         
    79         f2[i] = L;
    80     }
    81     
    82     for(int i = 1; i <= n; i++)
    83       ans = max(ans, (S[f2[i]] - S[f1[i] - 1]) * A[i]);
    84       
    85     printf("%lld
    ", ans);
    86     
    87     return 0;
    88 }

    RMQ初始化o(nlogn),查询o(nlogn)。

    思路2:将A[i]从大到小排,用并查集维护每个元素的集合,每次将该元素左右的不小于该元素本身的元素合并进来,更新答案。

    正确性有待考察……以后补……

    并查集47ms还可以:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 const int maxn = 100000 + 10;
     7 int f[maxn], Min[maxn];
     8 long long Sum[maxn], _max = 0;
     9 int n, P[maxn];
    10 
    11 struct Node{
    12     int v, id;
    13     bool operator < (const Node& ths) const{
    14         return v < ths.v;
    15     }
    16 }A[maxn];
    17 
    18 void read(int& x){
    19     x = 0;
    20     int sig = 1;
    21     char ch = getchar();
    22     while(!isdigit(ch)){
    23         if(ch == '-') sig = -1;
    24         ch = getchar();
    25     }
    26     while(isdigit(ch)){
    27         x = 10 * x + ch - '0';
    28         ch = getchar();
    29     }
    30     x *= sig;
    31     return ;
    32 }
    33 void input(){
    34     read(n);
    35     for(int i = 1; i <= n; i++) read(P[i]), A[i].id = f[i] = i, A[i].v = Min[i] = Sum[i] = P[i];
    36     return ;
    37 }
    38 int findset(int x){
    39     return f[x] == x ? x : f[x] = findset(f[x]);
    40 }
    41 void merge(int d1, int d2){
    42     int f1 = findset(d1);
    43     int f2 = findset(d2);
    44     if(f1 != f2){
    45         Sum[f1] += Sum[f2];
    46         Min[f1] = min(Min[f1], Min[f2]);
    47         f[f2] = f1;
    48         _max = max(_max, Sum[f1] * Min[f1]);
    49     }
    50     return ;
    51 }
    52 void work(){
    53     sort(A + 1, A + 1 + n);
    54     for(int i = n; i; i--){
    55         int x = A[i].id;
    56         if(x != 1 && P[x] <= P[x - 1]) merge(x, x - 1);
    57         if(x != n && P[x] <= P[x + 1]) merge(x, x + 1);
    58     }
    59     return ;
    60 }
    61 void output(){
    62     printf("%lld
    ", _max);
    63     return ;
    64 }
    65 int main(){
    66     input();
    67     work();
    68     output();
    69     return 0;
    70 }

    排序o(nlogn),扫描o(n),感觉很不错啊。

  • 相关阅读:
    IT学习 程序员 学习网址收藏
    PHP地图上的点文字标注
    php 三种文件下载的实现
    10个免费的jQuery富文本编辑器
    Docker Swarm(四)Volume 数据(挂载)持久化
    Docker Swarm(三)Service(服务)分配策略
    Docker Swarm(二)常用命令
    Docker Swarm(一)集群部署
    Linux——Shell脚本参数传递的2种方法
    Linux——系统时间、开机时间
  • 原文地址:https://www.cnblogs.com/chxer/p/4376631.html
Copyright © 2011-2022 走看看