zoukankan      html  css  js  c++  java
  • Friends and Subsequences(RMQ+二分||双端队列)

    链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=121473#problem/D

                                             
                                          Friends and Subsequences
    Time Limit:2000MS     Memory Limit:524288KB     64bit IO Format:%I64d & %I64u

    Description

    Mike and !Mike are old childhood rivals, they are opposite in everything they do, except programming. Today they have a problem they cannot solve on their own, but together (with you) — who knows?

    Every one of them has an integer sequences a and b of length n. Being given a query of the form of pair of integers (l, r), Mike can instantly tell the value of  while !Mike can instantly tell the value of .

    Now suppose a robot (you!) asks them all possible different queries of pairs of integers (l, r)(1 ≤ l ≤ r ≤ n) (so he will make exactlyn(n + 1) / 2 queries) and counts how many times their answers coincide, thus for how many pairs  is satisfied.

    How many occasions will the robot count?

    Input

    The first line contains only integer n (1 ≤ n ≤ 200 000).

    The second line contains n integer numbers a1, a2, ..., an ( - 109 ≤ ai ≤ 109) — the sequence a.

    The third line contains n integer numbers b1, b2, ..., bn ( - 109 ≤ bi ≤ 109) — the sequence b.

    Output

    Print the only integer number — the number of occasions the robot will count, thus for how many pairs  is satisfied.

    Sample Input

    Input
    6
    1 2 3 2 1 4
    6 7 1 2 3 2
    Output
    2
    Input
    3
    3 3 3
    1 1 1
    Output
    0

    Hint

    The occasions in the first sample case are:

    1.l = 4,r = 4 since max{2} = min{2}.

    2.l = 4,r = 5 since max{2, 1} = min{2, 3}.

    There are no occasions in the second sample case since Mike will answer 3 to any query pair, but !Mike will always answer 1.

    题意:

       有两个等长的序列a、b,求出在相同[l,r]区间的情况下,有序列a的最大值等于序列b的最小值这种结果的区间的总数。

    解析:

       这个要用到RMQ这个知识点,RMQ的预处理和查询有相应的模板,自己可以百度去了解记忆一下。

       利用区间特性进行二分,固定区间左端点(注意区间左端点和二分左端点不一样)

       确定最边缘左端点。

       若二分形成的最小值小于最大值,这个区间可以通过减小右端点而最大值可以再变小,最小值可以再变大,说明仍可以左移区间右端点

       若最小值大于最大值,则说明a区间中的数都小于b区间的最小值,只能右移区间左端点。

       确定最边缘右端点和上诉一样。

       若相等,则根据当前是求右边界最左端还是最右端进行相应移动。

       求出每一区间左端点对应的区间右端点的两个位置极值,作差,求和,求得结果。

    注意:5-1<<1的结果是4<<1,即等于8。

             5-(1<<1)的结果是5-2,即等于3.

    源代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 using namespace std;
     5 int fa[200010][20];
     6 int fb[200010][20];
     7 int RMQ(int L,int R,int x)
     8 {
     9     int k=log((R-L+1)*1.0)/log(2.0);
    10     if(x==0)
    11     return max(fa[L][k],fa[R+1-(1<<k)][k]);
    12     else
    13     return min(fb[L][k],fb[R+1-(1<<k)][k]);
    14 }
    15 int main()
    16 {
    17     int n;
    18     scanf("%d",&n);
    19     int a,b;
    20     for(int i=0;i<n;i++)
    21         scanf("%d",&fa[i][0]);
    22     for(int i=0;i<n;i++)
    23         scanf("%d",&fb[i][0]);
    24     for(int j=1;(1<<j)<=n;j++)
    25         for(int i=0;i+(1<<j)<=n;i++)
    26         {
    27             fa[i][j]=max(fa[i][j-1],fa[i+(1<<(j-1))][j-1]);
    28             fb[i][j]=min(fb[i][j-1],fb[i+(1<<(j-1))][j-1]);
    29         }
    30     int l,r,ma,mb,st,en,mid;
    31     long long sum=0;
    32     for(int i=0;i<n;i++)     //固定查询的左端点
    33     {
    34         l=i;
    35         st=-1;
    36         r=n-1;
    37         while(l<=r)     //二分求取最边缘左端点
    38         {
    39             mid=(l+r)/2;
    40             ma=RMQ(i,mid,0);
    41             mb=RMQ(i,mid,1);
    42             if(ma>=mb)
    43             {
    44                 if(ma==mb) st=mid;
    45                 r=mid-1;
    46             }
    47             else
    48                 l=mid+1;
    49         }
    50         if(st==-1) continue;
    51         l=i;
    52         r=n-1;
    53         en=-1;
    54         while(l<=r)    //二分求取最边缘右端点
    55         {
    56             mid=(l+r)/2;
    57             ma=RMQ(i,mid,0);
    58             mb=RMQ(i,mid,1);
    59 
    60             if(ma>mb) r=mid-1;
    61             else
    62             {
    63                 if(ma==mb) en=mid;
    64                 l=mid+1;
    65             }
    66         }
    67         sum+=(en-st+1);
    68     }
    69     printf("%lld
    ",sum);
    70     return 0;
    71 }

    还有一种方法

    利用双端队列(即两端都可以插入和删除),即deque

    源代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int a[200010],b[200010];
     4 long long sum=0;
     5 int main()
     6 {
     7     int n;
     8     scanf("%d",&n);
     9     for(int i=1;i<=n;i++)
    10         scanf("%d",&a[i]);
    11     for(int i=1;i<=n;i++)
    12         scanf("%d",&b[i]);
    13     deque<int>x,y;
    14     for(int i=1,j=1;i<=n;i++)
    15     {
    16         while(!x.empty()&&a[x.back()]<=a[i]) x.pop_back();
    17         while(!y.empty()&&b[y.back()]>=b[i]) y.pop_back();
    18         x.push_back(i);
    19         y.push_back(i);
    20         while(j<=i&&(a[x.front()]-b[y.front()]>0))
    21         {
    22             j++;
    23             while(!x.empty()&&x.front()<j) x.pop_front();
    24             while(!y.empty()&&y.front()<j) y.pop_front();
    25         }
    26         if(!x.empty()&&!y.empty()&&a[x.front()]==b[y.front()])
    27             sum+=min(x.front(),y.front())-j+1;
    28     }
    29     printf("%lld
    ",sum);
    30     return 0;
    31 }
  • 相关阅读:
    团队-团队编程项目作业名称-最终程序
    《团队-中国象棋-项目总结》
    课后作业-阅读任务-阅读提问-4
    《20171130-构建之法:现代软件工程-阅读笔记4》
    《软件工程课程总结》
    《20171117-构建之法:现代软件工程-阅读笔记-3》
    -课后作业-阅读任务-阅读提问-3
    《团队-中国象棋-团队一阶段互评》
    《团队-中国象棋-开发文档》
    《结对-贪吃蛇-结对项目总结》
  • 原文地址:https://www.cnblogs.com/q-c-y/p/5665024.html
Copyright © 2011-2022 走看看