zoukankan      html  css  js  c++  java
  • BZOJ 4384: [POI2015]Trzy wieże

    4384: [POI2015]Trzy wieże

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 217  Solved: 61
    [Submit][Status][Discuss]

    Description

    给定一个长度为n的仅包含'B'、'C'、'S'三种字符的字符串,请找到最长的一段连续子串,使得这一段要么只有一种字符,要么有多种字符,但是没有任意两种字符出现次数相同。

    Input

    第一行包含一个正整数n(1<=n<=1000000),表示字符串的长度。
    第二行一个长度为n的字符串。

    Output

    包含一行一个正整数,即最长的满足条件的子串的长度。

    Sample Input

    9
    CBBSSBCSC

    Sample Output

    6

    HINT

    选择BSSBCS这个子串。

    Source

    [Submit][Status][Discuss]

    分析

    OTZ Claris

    OTZ LincHpin

    OTZ MirrorGray

    ——下面开始正文——

    子串只包含一种字符的情况特殊处理,一遍扫描就可以了。

    首先将字符串转换称数字串,分别用0,1,2替代B,C,S。

    设sum[i][j]表示前i(0<=i<=n)个数字中j(0<=j<=2)的出现次数,则题目要求可以翻译如下

    选取一段[lt + 1, rt],满足:

    sum[rt][0] - sum[lt][0] != sum[rt][1] - sum[lt][1]

    sum[rt][0] - sum[lt][0] != sum[rt][2] - sum[lt][2]

    sum[rt][1] - sum[lt][1] != sum[rt][2] - sum[lt][2]

    从Claris大神那里学到的机智转换——通过交换等式两边的元素,将lt和rt分离。

    sum[rt][0] - sum[rt][1] != sum[lt][0] - sum[lt][1]

    sum[rt][0] - sum[rt][2] != sum[lt][0] - sum[lt][2]

    sum[rt][1] - sum[rt][2] != sum[lt][1] - sum[lt][2]

    这看起来就神清气爽多了,问题就转换成了——

    每个点上有一个三元组(x,y,z),以及一个id,求对于每个点来说,和它的三元组完全不同的id相距最远的点。

    将(x,y,z,id)按照x从小到大排序,这样就可以保证x的不同了。

    然后把y当作树状数组下标维护id的最大、最小值,这样查询的时候避开自己y的地方就可以保证y也不同了。

    可以z还可能相同,所以要维护次优解,且强制最优解和次优解的z不同。当最优解的z和当前点的z相同时,选择用次优解来更新即可。这样就保证z也不同了。

    然而并不清楚Claris大神是怎么用64行写完的,但也不代表我写200+行就有多麻烦,至少不是很费脑子(才怪)。

    代码

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 1000005;
      4 const int inf = 1e9 + 7;
      5 
      6 int n, m;
      7 
      8 int h[N];
      9 
     10 char s[N];
     11 
     12 int sum[3];
     13 
     14 int answer;
     15 
     16 struct Point
     17 {
     18     int id, x, y, z;
     19     
     20     Point(void) {};
     21     Point(int i, int a, int b, int c)
     22     {
     23         id = i;
     24         x = a;
     25         y = b;
     26         z = c;
     27     }
     28     
     29     friend bool operator < (const Point &a, const Point &b)
     30     {
     31         return a.x < b.x;
     32     }
     33 }p[N];
     34 
     35 struct Pair
     36 {
     37     int val, pos;
     38     
     39     Pair(void) {};
     40     
     41     Pair(int a, int b)
     42     {
     43         val = a;
     44         pos = b;
     45     }
     46     
     47     friend bool operator ^ (const Pair &a, const Pair &b)
     48     {
     49         return a.pos != b.pos;
     50     }
     51     
     52     friend bool operator < (const Pair &a, const Pair &b)
     53     {
     54         return a.val < b.val;
     55     }
     56     
     57     friend bool operator > (const Pair &a, const Pair &b)
     58     {
     59         return a.val > b.val;
     60     }
     61 };
     62 
     63 struct MinMax
     64 {
     65     Pair min0;
     66     Pair min1;
     67     Pair max0;
     68     Pair max1;
     69     
     70     MinMax(void)
     71     {
     72         min0 = Pair(inf, -inf);
     73         min1 = Pair(inf, -inf);
     74         max0 = Pair(-inf, -inf);
     75         max1 = Pair(-inf, -inf);
     76     }
     77     
     78     MinMax(int val, int pos)
     79     {
     80         min0 = max0 = Pair(val, pos);
     81         min1 = Pair(inf, -inf);
     82         max1 = Pair(-inf, -inf);
     83     }
     84     
     85     friend MinMax operator + (const MinMax &a, const MinMax &b)
     86     {
     87         MinMax r;
     88         
     89         if (a.min0 < b.min0)
     90         {
     91             r.min0 = a.min0;
     92             if (a.min1 < b.min0)
     93                 r.min1 = a.min1;
     94             else if (a.min0 ^ b.min0)
     95                 r.min1 = b.min0;
     96             else if (a.min1 < b.min1)
     97                 r.min1 = a.min1;
     98             else
     99                 r.min1 = b.min1;
    100         }
    101         else
    102         {
    103             r.min0 = b.min0;
    104             if (b.min1 < a.min0)
    105                 r.min1 = b.min1;
    106             else if (a.min0 ^ b.min0)
    107                 r.min1 = a.min0;
    108             else if (b.min1 < a.min1)
    109                 r.min1 = b.min1;
    110             else
    111                 r.min1 = a.min1;
    112         }
    113         
    114         
    115         if (a.max0 > b.max0)
    116         {
    117             r.max0 = a.max0;
    118             if (a.max1 > b.max0)
    119                 r.max1 = a.max1;
    120             else if (a.max0 ^ b.max0)
    121                 r.max1 = b.max0;
    122             else if (a.max1 > b.max1)
    123                 r.max1 = a.max1;
    124             else
    125                 r.max1 = b.max1;
    126         }
    127         else
    128         {
    129             r.max0 = b.max0;
    130             if (b.max1 > a.max0)
    131                 r.max1 = b.max1;
    132             else if (a.max0 ^ b.max0)
    133                 r.max1 = a.max0;
    134             else if (b.max1 > a.max1)
    135                 r.max1 = b.max1;
    136             else
    137                 r.max1 = a.max1;
    138         }
    139         
    140         return r;
    141     }
    142 };
    143 
    144 struct BIT
    145 {
    146     MinMax tree[N];
    147     
    148     int lowbit(int x)
    149     {
    150         return x & -x;
    151     }
    152     
    153     MinMax query(int p)
    154     {
    155         MinMax r;
    156         
    157         while (p)
    158         {
    159             r = r + tree[p];
    160             p -= lowbit(p);
    161         }
    162         
    163         return r;
    164     }
    165     
    166     void insert(int p, MinMax v)
    167     {
    168         while (p <= m)
    169         {
    170             tree[p] = tree[p] + v;
    171             p += lowbit(p);
    172         }
    173     }
    174 }lt, rt;
    175 
    176 signed main(void)
    177 {
    178     scanf("%d%s", &n, s + 1);
    179     
    180     for (int i = 1, j = 0; i <= n; ++i)
    181     {
    182         if (s[i] == s[i - 1])
    183             answer = std::max(answer, ++j);
    184         else
    185             answer = std::max(answer, j = 1);
    186     }
    187     
    188     for (int i = 1; i <= n; ++i)
    189     {
    190         switch (s[i])
    191         {
    192             case 'B': ++sum[0]; break;
    193             case 'C': ++sum[1]; break;
    194             case 'S': ++sum[2]; break;
    195         }
    196         
    197         p[i] = Point(
    198             i,
    199             sum[0] - sum[1],
    200             sum[1] - sum[2],
    201             sum[2] - sum[0]
    202         );
    203         
    204         h[i] = p[i].y;
    205     }
    206     
    207     p[++n] = Point(0, 0, 0, 0);
    208         
    209     std::sort(p + 1, p + 1 + n);
    210     std::sort(h + 1, h + 1 + n);
    211     
    212     m = std::unique(h + 1, h + 1 + n) - h - 1;
    213     
    214     for (int i = 1; i <= n; ++i)
    215         p[i].y = std::lower_bound(h + 1, h + 1 + m, p[i].y) - h;
    216         
    217     for (int i = 1, j = 1; i <= n; i = j)
    218     {
    219         while (j <= n && p[i].x == p[j].x)++j;
    220         
    221         for (int k = i; k < j; ++k)
    222         {
    223             MinMax l = lt.query(p[k].y - 1);
    224             MinMax r = rt.query(m - p[k].y);
    225             
    226             if (l.min0.pos != p[k].z)
    227                 answer = std::max(answer, p[k].id - l.min0.val);
    228             else
    229                 answer = std::max(answer, p[k].id - l.min1.val);
    230             
    231             if (l.max0.pos != p[k].z)
    232                 answer = std::max(answer, l.max0.val - p[k].id);
    233             else
    234                 answer = std::max(answer, l.max1.val - p[k].id);
    235                 
    236             if (r.min0.pos != p[k].z)
    237                 answer = std::max(answer, p[k].id - r.min0.val);
    238             else
    239                 answer = std::max(answer, p[k].id - r.min1.val);
    240             
    241             if (r.max0.pos != p[k].z)
    242                 answer = std::max(answer, r.max0.val - p[k].id);
    243             else
    244                 answer = std::max(answer, r.max1.val - p[k].id);
    245         }
    246         
    247         for (int k = i; k < j; ++k)
    248         {
    249             lt.insert(p[k].y, MinMax(p[k].id, p[k].z));
    250             rt.insert(m + 1 - p[k].y, MinMax(p[k].id, p[k].z));
    251         }
    252     }
    253     
    254     printf("%d
    ", answer);
    255 }
    BZOJ_4384.cpp

    @Author: YouSiki

  • 相关阅读:
    linux 系统账户 和 普通账户 的区别
    supervisor 相关命令
    linux 动态链接库查找方法;查找动态链接库位置; LIBRARY_PATH 和 LD_LIBRARY_PATH 的区别;LD_LIBRARY_PATH and LD_RUN_PATH的区别;MACOS 下查看动态链接库方法
    Ubuntu 一键伪装成Win 10,Kali Linux 2019 kali-undercover软件嫁接;Ubuntu 1804 使用 kali-undercover;
    C 实战练习题目30 – 回文数
    C 实战练习题目29
    C 实战练习题目28
    C 实战练习题目27
    C 实战练习题目26 -递归法求阶乘
    C 实战练习题目25
  • 原文地址:https://www.cnblogs.com/yousiki/p/6061101.html
Copyright © 2011-2022 走看看