zoukankan      html  css  js  c++  java
  • 二分+RMQ/双端队列/尺取法 HDOJ 5289 Assignment

    题目传送门

     1 /*
     2     题意:问有几个区间最大值-最小值 < k
     3     解法1:枚举左端点,二分右端点,用RMQ(或树状数组)求区间最值,O(nlog(n))复杂度
     4     解法2:用单调队列维护最值,O(n)复杂度,用法
     5     解法3:尺取法,用mutiset维护最值
     6 */
     7 #include <cstdio>
     8 #include <algorithm>
     9 #include <cstring>
    10 #include <cmath>
    11 using namespace std;
    12 
    13 typedef long long ll;
    14 const int MAXN = 1e5 + 10;
    15 const int INF = 0x3f3f3f3f;
    16 int a[MAXN];
    17 int mn[MAXN][20], mx[MAXN][20];     //最多能保存524288的长度
    18 
    19 int RMQ(int l, int r)   {
    20     int k = 0;  while (1<<(k+1) <= r - l + 1) k++;      //令k为满足1<<k <= r-l+1的最大整数
    21     int MAX = max (mx[l][k], mx[r-(1<<k)+1][k]);        //意思是区间最左边1<<k长度的最大值和最右边1<<k长度的最大值
    22     int MIN = min (mn[l][k], mn[r-(1<<k)+1][k]);        //可能有重叠的地方
    23     return MAX - MIN;
    24 }
    25 
    26 int main(void)  {       //HDOJ 5289 Assignment
    27     freopen ("B.in", "r", stdin);
    28 
    29     int t;  scanf ("%d", &t);
    30     while (t--) {
    31         int n, k;  scanf ("%d%d", &n, &k);
    32         for (int i=1; i<=n; ++i)    {
    33             scanf ("%d", &a[i]);
    34             mn[i][0] = mx[i][0] = a[i];
    35         }
    36         for (int j=1; (1<<j)<=n; ++j)   {
    37             for (int i=1; i+(1<<j)-1<=n; ++i)   {
    38                 mn[i][j] = min (mn[i][j-1], mn[i+(1<<(j-1))][j-1]);     //mn[i][j]意思是从i开始,长度1<<j的区间的最小值
    39                 mx[i][j] = max (mx[i][j-1], mx[i+(1<<(j-1))][j-1]);
    40             }
    41         }
    42 
    43         ll ans = 0;
    44         for (int i=1; i<=n; ++i)    {
    45             int l = i, r = n;
    46             while (l + 1 < r)   {       //二分使得l, r最远
    47                 int mid = (l + r) >> 1;
    48                 if (RMQ (i, mid) < k)   l = mid;
    49                 else    r = mid;
    50             }
    51             if (RMQ (i, r) < k) {       //此时[l, r](l+1==r) 其中一个一定满足条件
    52                 ans += (r - i + 1);
    53             }
    54             else    {
    55                 ans += (l - i + 1);
    56             }
    57         }
    58         printf ("%I64d
    ", ans);
    59     }
    60 
    61     return 0;
    62 }
     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstring>
     4 #include <cmath>
     5 using namespace std;
     6 
     7 typedef long long ll;
     8 const int MAXN = 1e5 + 10;
     9 const int INF = 0x3f3f3f3f;
    10 int a[MAXN], n;
    11 struct BIT  {
    12     int mn[MAXN], mx[MAXN];
    13 
    14     void init(void) {
    15         memset (mn, INF, sizeof (mn));
    16         memset (mx, 0, sizeof (mx));
    17     }
    18     void add_min(int i, int x)  {
    19         while (i <= n)    {
    20             mn[i] = min (mn[i], x); i += i & (-i);
    21         }
    22     }
    23     int query_min(int i)    {
    24         int res = INF;
    25         while (i > 0)   {
    26             res = min (res, mn[i]); i -= i & (-i);
    27         }
    28         return res;
    29     }
    30     void add_max(int i, int x)  {
    31         while (i <= n)    {
    32             mx[i] = max (mx[i], x); i += i & (-i);
    33         }
    34     }
    35     int query_max(int i)    {
    36         int res = 0;
    37         while (i > 0)   {
    38             res = max (res, mx[i]); i -= i & (-i);
    39         }
    40         return res;
    41     }
    42 }bit;
    43 
    44 int main(void)  {
    45     //freopen ("B.in", "r", stdin);
    46 
    47     int t;  scanf ("%d", &t);
    48     while (t--) {
    49         int k;  scanf ("%d%d", &n, &k);
    50         for (int i=1; i<=n; ++i)    {
    51             scanf ("%d", &a[i]);
    52         }
    53         
    54         ll ans = 0; bit.init ();
    55         for (int i=n; i>=1; --i)    {       //树状数组的特点,倒过来插入,求[i, n]区间
    56             bit.add_min (i, a[i]);
    57             bit.add_max (i, a[i]);
    58             int l = i, r = n;
    59             while (l <= r)  {
    60                 int mid = (l + r) >> 1;
    61                 int MAX = bit.query_max (mid);
    62                 int MIN = bit.query_min (mid);
    63                 if (MAX - MIN >= k) r = mid - 1;
    64                 else    l = mid + 1;
    65             }
    66             ans += l - i;
    67         }
    68         printf ("%I64d
    ", ans);
    69     }
    70 
    71     return 0;
    72 }
    树状数组
     1 /*
     2     维护递增和递减的队列,当队首满足条件时,添加个数,再在从后添加元素,否则pop_front
     3 */
     4 #include <cstdio>
     5 #include <algorithm>
     6 #include <cstring>
     7 #include <queue>
     8 using namespace std;
     9 
    10 typedef long long ll;
    11 const int MAXN = 1e5 + 10;
    12 const int INF = 0x3f3f3f3f;
    13 struct Node {
    14     int v, p;
    15 };
    16 int a[MAXN];
    17 
    18 int main(void)  {
    19     //freopen ("B.in", "r", stdin);
    20 
    21     int t;  scanf ("%d", &t);
    22     while (t--) {
    23         int n, k;   scanf ("%d%d", &n, &k);
    24         for (int i=1; i<=n; ++i)    scanf ("%d", &a[i]);
    25         
    26         deque<Node> Q1, Q2; ll ans = 0; int head = 1;
    27         for (int i=1; i<=n; ++i)    {
    28             Node now = (Node){a[i], i};
    29             while (!Q1.empty ())    {       //递减  队首max
    30                 Node tmp = Q1.back ();
    31                 if (now.v > tmp.v)  Q1.pop_back ();
    32                 else    break;
    33             }
    34             Q1.push_back (now);
    35             while (!Q2.empty ())    {       //递增  队首min
    36                 Node tmp = Q2.back ();
    37                 if (now.v < tmp.v)  Q2.pop_back ();
    38                 else    break;
    39             }
    40             Q2.push_back (now);
    41 
    42             if (i == 1) ans++;
    43             else    {
    44                 while (true)    {
    45                     Node big = Q1.front ();
    46                     Node small = Q2.front ();
    47                     if (big.v - small.v < k)    break;
    48                     else    {
    49                         if (small.p < big.p)    {
    50                             head = small.p + 1; Q2.pop_front ();
    51                         }
    52                         else    {
    53                             head = big.p + 1;   Q1.pop_front ();
    54                         }
    55                     }
    56                 }
    57                 ans += i - head + 1;
    58             }
    59         }
    60         printf ("%I64d
    ", ans);
    61     }
    62 
    63     return 0;
    64 }
    单调队列
     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstring>
     4 #include <set>
     5 #include <cmath>
     6 using namespace std;
     7 
     8 typedef long long ll;
     9 const int MAXN = 1e5 + 10;
    10 const int INF = 0x3f3f3f3f;
    11 multiset<int> S;
    12 int a[MAXN];
    13 
    14 int main(void)  {
    15     //freopen ("B.in", "r", stdin);
    16 
    17     int t;  scanf ("%d", &t);
    18     while (t--) {
    19         int n, k;   scanf ("%d%d", &n, &k);
    20         for (int i=1; i<=n; ++i)    {
    21             scanf ("%d", &a[i]);
    22         }
    23 
    24         S.clear (); S.insert (a[1]);
    25         int l = 1, r = 2;   ll ans = 0;
    26         int mn, mx;
    27         while (true)   {
    28             if (S.size ())  {
    29                 mn = *S.begin ();
    30                 mx = *S.rbegin ();
    31                 if (abs (a[r] - mn) < k && abs (a[r] - mx) < k) {
    32                     ans += S.size ();   S.insert (a[r++]);
    33                     if (r > n) break;
    34                 }
    35                 else    {
    36                     if (S.size ())  S.erase (S.find (a[l]));
    37                     l++;
    38                 }
    39             }
    40             else    {
    41                 l = r;  S.insert (a[r++]);
    42                 if (r > n) break;
    43             }
    44         }
    45         
    46         printf ("%I64d
    ", ans + n);
    47     }
    48 
    49     return 0;
    50 }
    尺取法(multiset)
    编译人生,运行世界!
  • 相关阅读:
    Vulkan
    C# Optimization
    C# Bridge Pattern(Handle/Body)
    Favorite Games
    Unity Particle System Sorting Order
    UGUI
    C# Language Specification
    接口的显式实现和隐式实现
    C#反射机制
    wcf 使用sqlMembership证书认证
  • 原文地址:https://www.cnblogs.com/Running-Time/p/4667023.html
Copyright © 2011-2022 走看看