zoukankan      html  css  js  c++  java
  • SCOI2014 方伯伯的玉米田 题解

    可能其它还没写完的几篇随笔要搁一会儿,反正先写写题解

    \(1-n\)的一个序列,值分别为\(a[1]\)\(a[2]...a[n]\),最多可进行\(K\)次操作,每次操作可以使\(l-r\)区间内的所有元素值加一(\(l\)\(r\)自选)。操作完后,还可以删除任意多个元素(不需要连续),使剩下的元素构成一个不下降序列,问这个子序列最多有多少个元素

    首先,经过初步思考与推测可以得出一个结论,就是每次操作的区间中\(r\)一定为\(n\),因为最终要构成的是一个不下降的子序列,所以若\(r\neq n\),那么后面的元素相对于前面的元素就会下降多个单位,最终导致低于前面的元素而被删除,所以剩下的元素也会相应减少,不满足最优的条件

    有了这个性质以后,我们便可以设\(dp[i][j]\)表示前\(i\)个元素共计被加了\(j\)次后构成的最后一个元素的下标为\(i\)为最长不下降子序列的长度(为什么\(i\)一定要选?因为若是不选那么我们就不知道当前序列最后一个元素是什么,然后就无法在转移时比较高度来构成不下降序列了),那么显然,第\(i\)个元素一定被加了\(j\)次,所以其高度为\(a[i]+j\)。(其实也可以理解成前\(i\)个元素被加了\(j\)次并在\(1-i\)中移除了部分且移除了\(i+1-n\)的全部元素使得剩下的元素变成不下降的序列)

    接下来状态转移,首先二重循环枚举\(i\)\(j\)少不了,然后再枚举\(k\)\(p\),表示要从\(dp[k][p]\)这个状态转移过来(相当于\(i+1-k-1\)的元素都被删掉了),所以我们有如下的状态转移方程:

    \(dp[i][j]=max\left\{dp[k][p]+1\right\},a[k]+p \le a[i]+j,p \le j,k<i\)

    不幸的是,这样转移的复杂度是\(O(n^2k^2)\)的,实在是难以接受,所以还是要优化一下。发现我们每次只是在满足\(a[k]+p \le a[i]+j,p \le j,k<i\)的情况下找到一个最大的\(dp[k][p]+1\)并更新当前状态,然后再用这个状态更新之后的状态,有些像线段树的单点查询与修改,但是仅仅是这两个操作我们就不一定要用线段树了,树状数组也可以实现,而且无论在码长还是在常数上都比线段树优秀,所以最终选用树状数组优化

    考虑到这题有两个限制条件,即需要满足\(a[k]+p \le a[i]+j\)\(p \le j\)(剩下的一个限制条件在处理时已经被考虑到了,毕竟是从\(1-n\)循环的,所以在查询\((i,j)\)的值时,一定是在\(1...i-1\)的范围内查询、转移的),所以考虑开一个二维的树状数组。二维的树状数组与一维相差不大,我们可以这样理解:例如开一个\(n*n\)的二维的树状数组,那么我们可以先把它们当成\(n\)个不相关的长度为\(n\)的树状数组,按照一般的方法计算好\(n\)个树状数组,然后把这\(n\)个树状数组再按照一般的方法在对应位置上累加一下,我讲得可能一定不太清楚,所以可以看看这位的CSDN博客,然后我们只要在\((a[i]+j,j+1)\)的范围内查询、修改就可以了,为什么\(j\)需要加一?因为\(j\)可能为零不太好处理......这样的话,复杂度就可以被优化到\(O(nklognlogk)\),于是本题就可以通过了,代码如下:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int N=1e4+10;
    const int M=5e2+10;
    int n,k,a[N],tmp,c[N*2][M],ans,maxn;
    int lowbit(int x){return x&-x;}
    void update(int x,int y,int p){
        for(register int i=x;i<=maxn+k+1;i+=lowbit(i))
            for(register int j=y;j<=k+1;j+=lowbit(j))
                c[i][j]=max(c[i][j],p);
    }
    int query(int x,int y){
        int sum=0;
        for(register int i=x;i;i-=lowbit(i))
            for(register int j=y;j;j-=lowbit(j))
                sum=max(sum,c[i][j]);
        return sum;
    }
    int main(){
        scanf("%d%d",&n,&k);
        for(register int i=1;i<=n;i++){scanf("%d",&a[i]);maxn=max(maxn,a[i]);}
        for(register int i=1;i<=n;i++)
            for(register int j=k;j>=0;j--){//倒序处理了解一下,不然正序的话j是递增的,后面的j在查询时会把前面的j刚修改过的值带入计算
                tmp=query(a[i]+j,j+1)+1;
                ans=max(ans,tmp);
                update(a[i]+j,j+1,tmp);}
        printf("%d\n",ans);
        return 0;
    }
    
  • 相关阅读:
    部署 AppGlobalResources 到 SharePoint 2010
    还原一个已删除的网站集
    使用仪表板设计器配置级联筛选器 (SharePoint Server 2010 SP1)
    File or arguments not valid for site template
    Pex and Moles Documentation
    Content Query Webpart匿名访问
    Running Moles using NUnit Console from Visual Studio
    Calling a WCF Service using jQuery in SharePoint the correct way
    Updating Content Types and Site Columns That Were Deployed as a Feature
    asp.net中判断传过来的字符串不为空的代码
  • 原文地址:https://www.cnblogs.com/ForwardFuture/p/9272989.html
Copyright © 2011-2022 走看看