纪中集训2019.08.20JZOJ6310Global warming

Posted hansue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了纪中集训2019.08.20JZOJ6310Global warming相关的知识,希望对你有一定的参考价值。

题目链接

 

题意:

  给出一个长度为$n$的序列$\a_n\$。

  已知一个正整数$x$,你有一次机会指定区间$[l,r]$,令$\forall i\in [l,r],\;a_i=a_i+d\,(|d|\le x)$。

  求最大化的最长上升子序列的长度。

  $1 \le n \le 2 \times 10^5 , \quad 1 \le a_i,x \le 10^9$且均为正整数。

 

分析:

  可以很容易发现三个性质:

  性质一:抬升$[l,r]$不优于抬升$[l,n]$,降低$[l,r]$不优于降低$[1,l]$。

  性质二:降低$[1,p]$等价于抬升$[p+1,n]$。

  性质三:抬升/降低$k$不优于抬升/降低$x$。

  由此很容易想到分成两块求部分答案,再拼成总答案。

  但这并不是简单地把向左/右拓展的上升子序列或者它们的前/后缀最大值在某个分割点加起来。怎么办呢?

  考虑在从左向右做$LIS$时加上一些限制,即$a_i$必须不超过$\mathopmin \limits _j=i+1 ^n \ a_j \$才能加入$LIS$中。

  这个做法显然是错误的,因为这样会遗漏很多贡献。如果坚持用“限制法”来做,那么$i$每移动一次,限制更新了,都要把之前的全部重算一次,这样才能正确。

  等一下,是我们的思路出了问题吗?有这么复杂吗?

  让我们冷静一下,现在我们在求什么?

  一些“左拼图”候选。

  “限制法”尝试让现在求得的“左拼图”能对上所有“右拼图”,这是不现实的。

  所以我们应该考虑的是怎么样让对应长度的“拼图”“契合”。应该让$a_i$到左侧的$LIS$中去找到位置。

  来一个规范一点的定义:

  设$f_i$表示将$[1,i-1]$降低时,以$a_i$为结尾的最长上升子序列长度。

  那么我们正着做$LIS$时把每个$a_i-x$放入单调数组里,当$2\le i\le n$时$a_i$在单调数组里的合法位置就是$f_i$了。

  之后再反着做$LIS$,设单调数组在$i$时的长度为$l_i$,那么答案是$max \ \, \mathopmax\limits^n_i=2\ f_i + l_i \ \, , \, l_1 \, \$。

 

实现(100分):

技术图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define IL inline
using namespace std;
const int N=2e5;
const int inf=0x3f3f3f3f;

    int n,x,a[N+3];
    int f[N+3];
    
IL bool cmp1(int p,int q)
    return p>=q;
    

    
IL bool cmp2(int p,int q)
    return p<=q;
    


IL int bins(int *a,int l,int r,int x,bool cmp(int p,int q))
    int mid,ans=0;
    while(l<=r)
        mid=(l+r)>>1;
        if(cmp(a[mid],x))
            ans=mid;
            r=mid-1;
            
        
        else 
            l=mid+1;
        
    
    return ans;
    


int main()
    freopen("glo.in","r",stdin);
    freopen("glo.out","w",stdout);
    
    scanf("%d%d",&n,&x);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    
    int s[N+3],k;
    memset(s,0x3f,sizeof s);
    s[0]=-inf;    k=0;
    for(int i=1;i<=n;i++)
        f[i]=max(0,bins(s,1,k+1,a[i],cmp1)-1);
        int p=bins(s,1,k+1,a[i]-x,cmp1);
        s[p]=a[i]-x;    k=max(k,p);
        
    
    
    int ans;
    memset(s,0,sizeof s);
    s[0]=inf;
    k=ans=0;
    for(int i=n;i>=1;i--)
        int p=bins(s,1,k+1,a[i],cmp2);
        s[p]=a[i];    k=max(k,p);
        ans=max(ans,p+f[i]);
        
    
    
    printf("%d",ans);
    
    return 0;

View Code

 

小结:

  显然性质$\rightarrow$化归拆解问题$\rightarrow$合适地拼出答案。

以上是关于纪中集训2019.08.20JZOJ6310Global warming的主要内容,如果未能解决你的问题,请参考以下文章

纪中模拟2019.08.17JZOJ3503粉刷

纪中模拟2019.08.03JZOJ1308取数游戏

木兮的纪中集训感想

纪中集训2019.11.08

纪中集训2019.11.09

纪中集训的第七天