• [Codeforces526F]Pudding Monsters 分治


    F. Pudding Monsters
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes

    In this problem you will meet the simplified model of game Pudding Monsters.

    An important process in developing any game is creating levels. A game field in Pudding Monsters is an n × n rectangular grid, n of its cells contain monsters and some other cells contain game objects. The gameplay is about moving the monsters around the field. When two monsters are touching each other, they glue together into a single big one (as they are from pudding, remember?).

    Statistics showed that the most interesting maps appear if initially each row and each column contains exactly one monster and the rest of map specifics is set up by the correct positioning of the other game objects.

    A technique that's widely used to make the development process more efficient is reusing the available resources. For example, if there is a large n × n map, you can choose in it a smaller k × k square part, containing exactly k monsters and suggest it as a simplified version of the original map.

    You wonder how many ways there are to choose in the initial map a k × k (1 ≤ k ≤ n) square fragment, containing exactly k pudding monsters. Calculate this number.

    Input

    The first line contains a single integer n (1 ≤ n ≤ 3 × 105) — the size of the initial field.

    Next n lines contain the coordinates of the cells initially containing monsters. The i-th of the next lines contains two numbers ri, ci(1 ≤ ri, ci ≤ n) — the row number and the column number of the cell that initially contains the i-th monster.

    It is guaranteed that all ri are distinct numbers and all ci are distinct numbers.

    Output

    Print the number of distinct square fragments of the original field that can form a new map.

    Examples
    input
    5
    1 1
    4 3
    3 2
    2 4
    5
    output
    10

    题解:

    考试的时候这道题真是吓到我了。。一开始以为是一道单纯的数数题,后来发现并不简单。。。

    我们把这个棋盘模型抽象一下,这个棋盘由于

    Statistics showed that the most interesting maps appear if initially each row and each column contains exactly one monster and the rest of map specifics is set up by the correct positioning of the other game objects.

    也就是说,一行一列只有1个怪物,所以我们可以把它抽象为(化简为)一个1~n的排列

    如果定义max(l,r)为区间[l,r]的最大值,min(l,r)为区间[l,r]的最小值,

    我们需要的目标正方形,就对应这个排列中的某一个区间[l,r],并且满足max(l,r)-min(l,r)==r-l

    接下来是关键的一步:我们考虑分治统计这些合法区间(似乎有一些类似cdq?)。

    也就是说,如果设f(l,r)为区间[l,r]的合法区间数量,mi=(l+r)>>1

    那么f(l,r)=f(l,mi)+f(mi+1,r)+『跨中点的合法解数量』

    接下来我们考虑如何统计跨中点的合法解数量。

    对于跨中点的合法解,其可能情况有4种:

    1°max(l,r),min(l,r)均在左侧

    2°max(l,r),min(l,r)均在右侧

    3°max(l,r)在左侧,min(l,r)在右侧

    4°max(l,r)在右侧,min(l,r)在左侧

    简单来说,就是极值“在同侧”和“在异侧”两种情况

    如果极值在同侧,我们可以枚举一个端点,并且计算出区间长度,从而得到另外一个端点,

    最后判断是否合法,也即判断另外一侧是否有更大/小的极值

    如果极值在异侧,我们依旧枚举其中一个端点,

    (我们这里仅讨论最小值在左侧的情况,最小值在右侧的情况是与此对称的)

    然后我们考虑上面的式子max(mi+1,r)-min(l,mi)==r-l

    移项可得max(mi+1,r)-r==min(l,mi)-l

    这样我们就可以枚举左端点,再用桶维护每个min(l,mi)-l对应的合法解个数(通过扫描右区间可得)

    但要注意,min(l,mi)-l可能是负值,因此我们要给他加上一个较大值(比如N)

    最后统计答案即可。代码见下:

     1 #include <cstdio>
     2 #include <cstring>
     3 using namespace std;
     4 typedef long long LL;
     5 const int N=300010;
     6 int n,A[N],cnt[N*2+100],maxl[N],minl[N],maxr[N],minr[N];
     7 inline int max(int a,int b){return a>b?a:b;}
     8 inline int min(int a,int b){return a<b?a:b;}
     9 LL divide(int l,int r)
    10 {
    11     if(l==r)return 1;
    12     register int mi=(l+r)>>1,i,j,k;
    13     LL ret=divide(l,mi)+divide(mi+1,r);
    14     maxl[mi]=minl[mi]=A[mi],maxr[mi+1]=minr[mi+1]=A[mi+1];
    15     for(i=mi-1;i>=l;--i)maxl[i]=max(maxl[i+1],A[i]),minl[i]=min(minl[i+1],A[i]);
    16     for(i=mi+2;i<=r;++i)maxr[i]=max(maxr[i-1],A[i]),minr[i]=min(minr[i-1],A[i]);
    17     for(i=l;i<=mi;++i)
    18     {
    19         j=i+maxl[i]-minl[i];
    20         if(j<=r&&j>mi&&maxr[j]<maxl[i]&&minr[j]>minl[i])ret++;
    21     }
    22     for(i=r;i>mi;--i)
    23     {
    24         j=i-(maxr[i]-minr[i]);
    25         if(j>=l&&j<=mi&&maxl[j]<maxr[i]&&minl[j]>minr[i])ret++;
    26     }
    27     for(i=mi,j=mi+1,k=mi;i>=l;--i)
    28     {
    29         while(j<=r&&maxr[j]<maxl[i])--cnt[maxr[j]-j+N],++j;
    30         while(k<r&&minr[k+1]>minl[i])++k,++cnt[maxr[k]-k+N];
    31         ret+=max(cnt[minl[i]-i+N],0);
    32     }
    33     for(i=mi+1;i<=r;++i)cnt[maxr[i]-i+N]=0;
    34     for(i=mi,j=mi+1,k=mi;i>=l;--i)
    35     {
    36         while(j<=r&&minr[j]>minl[i])--cnt[minr[j]+j],++j;
    37         while(k<r&&maxr[k+1]<maxl[i])++k,++cnt[minr[k]+k];
    38         ret+=max(cnt[maxl[i]+i],0);
    39     }
    40     for(i=mi+1;i<=r;++i)cnt[minr[i]+i]=0;
    41     return ret;
    42 }
    43 int main()
    44 {
    45     scanf("%d",&n);int a,b;register int i,j;
    46     for(i=1;i<=n;++i)scanf("%d%d",&a,&b),A[a]=b;
    47     printf("%I64d
    ",divide(1,n));
    48 }

     这道题的代码实现不是很难,但是这种模型的转换,以及分治的想法是很excellent的,真是长见识了。

    我不经常用分治的方法解题……以后刷题的时候要多想想这方面的解法了。

  • 相关阅读:
    日期时间格式或封装,已经互相转换,抽出来日后方便自己开发,之前用作在mpvue的框架开发小程序中
    微信小程序授权方法全能,当用户拒绝或者首次进来的,都可以弹起授权提示,主要是用wx.getSetting,还有wx.authorize,最后的wx.openSetting
    JavaScript封装自己的一个弹窗,是双按钮的,比较简单一些 ,其中引用了jQuery来写的方法,最后暴露出去,有更好的建议欢迎评论 。。。。
    最近学习mpvue框架开发微信小程序,把wepy框架的项目实现到mpvue中,知道其中的一些两者之间的区别
    JavaScript中历史搜索记录的实现,在h5页面,引用jQuery写法,使用localStorage存储
    vue中实现双向数据绑定原理,使用了Object.defineproperty()方法,方法简单
    好好学习vue中 写了一些demo 希望自己能提升多一点 vue中实现父子组件之间的通信 相比我的上一篇非父子组件会简单些
    Java中Scanner类在nextInt()后无法输入nextLine()的问题
    mybatis中#{}和${}的区别及order by的sql注入问题
    Intellij常用设置及快捷键
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7495870.html
Copyright © 2020-2023  润新知