• [51nod1482]部落信号 单调栈


    ~~~题面~~~

    题解:

      可以发现这是一道单调栈的题目,首先来考虑数字没有重复时如何统计贡献。

      因为这是一个环,而如果我们从最高的点把环断开,并把最高点放在链的最后面(顺时针移动),那么因为在最高点两侧的点无法互相看见,相当于就把环转化为链的问题了。

      

      因此维护递减的单调栈,如果进来的点比栈顶高就弹出并统计1的贡献。

      但是这样会有遗漏,我们观察什么情况下会遗漏。

      因为是从1开始遍历,因此在前面的节点在遍历到n时完全有可能已经被弹走了,然而因为这是一个环,断开点(最高点)说不定还可以回头看见它。因此这种情况会被遗漏。

      但如果又反着统计又会统计重复,因此考虑不统计最高点的贡献,然后最后再暴力跑2遍统计断开点的贡献。

      但是数字可能有重复,怎么办?

      重复数字会带来很多细节上的问题,比如8333中有5的贡献,而直接弹走显然统计不到5.又比如最大值可能有很多个,因此会将整个数列分为很多小段,,,等等诸如此类。

      因此对于第一种情况,我们记录一下当前栈中每个数字有多少个,因为数字可能很大,但个数不多,因此一开始要离散化一下。

      对于第二种情况,可以在最后暴力统计一下最高点两两搭配的方案数。
      细节很多,注意调试&对拍

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define R register int
      4 #define AC 1001000
      5 #define LL long long
      6 
      7 int n, id, k, maxn, num, last, cnt;
      8 LL ans;
      9 int ss[AC], t[AC], tot[AC];
     10 int s[AC], top;
     11 bool vis[AC];
     12 
     13 inline int read()
     14 {
     15     int x = 0;char c = getchar();
     16     while(c > '9' || c < '0') c = getchar();
     17     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
     18     return x;
     19 }
     20 
     21 inline void upmax(int &a, int b)
     22 {
     23     if(b > a) a = b;
     24 }
     25 
     26 inline int get(int x)
     27 {
     28     if(x < 1) x += n;
     29     return x > n ? x - n : x;
     30 }
     31 
     32 int half(int x)
     33 {
     34     int l = 1, r = cnt;
     35     while(l < r)
     36     {
     37         int mid = (l + r) >> 1;
     38         if(ss[mid] == x) return mid;
     39         else if(ss[mid] < x) l = mid + 1;
     40         else r = mid - 1;
     41     }
     42     return l;
     43 }
     44 
     45 void pre()
     46 {
     47     n = read();
     48     for(R i = 1; i <= n; i ++) 
     49     {
     50         ss[i] = read();
     51         if(ss[i] > k) id = i, k = ss[i], num = 1;
     52         else if(ss[i] == k) ++ num;
     53     }
     54     id = get(id + 1);
     55     for(R i = 1; i <= n; i ++) t[i] = ss[get(id + i - 1)];
     56     sort(ss + 1, ss + n + 1);
     57     for(R i = 1; i <= n; i ++) 
     58         if(ss[i] != ss[i + 1]) ss[++cnt] = ss[i]; 
     59     for(R i = 1; i <= n; i ++) t[i] = half(t[i]);
     60     k = cnt;
     61 }
     62 
     63 /*8
     64 3 1 5 7 1 1 7 8 */
     65 void work()
     66 {
     67     for(R i = 1; i < n; i ++)//不统计中断处的
     68     {
     69         int tmp = (top && s[1] != t[i]);
     70     //    printf("%d
    ", top);        
     71         while(top && s[top] < t[i]) -- tot[s[top]], -- top, ++ ans;    
     72         if(top && s[top] != t[i]) ++ ans;
     73         ++ tot[t[i]], s[++top] = t[i];
     74         if(tot[t[i]] - 1) ans += tot[t[i]] - 1 + tmp;
     75     //    printf("%d
    ", top);
     76     }
     77     for(R i = 1; i <= n; i ++)
     78     {
     79         if(t[i] == k) break;
     80         if(vis[i]) continue;
     81         if(t[i] >= maxn && !vis[i]) ++ ans, vis[i] = true;
     82         upmax(maxn, t[i]);
     83     }
     84     maxn = 0;
     85     for(R i = n - 1; i; i --)
     86     {
     87         if(t[i] == k) break;
     88         if(t[i] >= maxn && !vis[i]) ++ ans, vis[i] = true;
     89         upmax(maxn, t[i]);
     90     }
     91     if(num > 1) ans += num * (num - 1) / 2 - (num - 1) * (num - 2) / 2;
     92     printf("%lld
    ", ans);
     93 }
     94 
     95 int main()
     96 {
     97 //    freopen("in.in", "r", stdin);
     98     pre();
     99     work();
    100 //    fclose(stdin);
    101     return 0;
    102 }
    View Code
  • 相关阅读:
    zend server 配置问题 ZendEnablerConf.xml
    ZendStudio 正式版注册破解
    eq几种样式
    js 简单语法 集合
    div上加连接》实用笔记
    VC解析XML使用CMarkup类解析XML
    用PNG透明图片和GDI+做不规则透明窗体"异形窗口"
    程序调试手记—解决Stack Overflow问题
    堆和栈的区别
    CString转换为char *
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9770185.html
Copyright © 2020-2023  润新知