Sweety

Practice makes perfect

导航

HZAU 1205 Sequence Number(最大值前后缀 +双指针 + 二分)

Posted on 2017-04-24 16:02  蓝空  阅读(208)  评论(0编辑  收藏  举报




先求求后面的最小值前缀,也就是预处理1~i的最小值,然后从右往左双指针,维护右端点>左端点,如果右端点<1~L的最小值,则移动右端点。

#include <bits/stdc++.h>
using namespace std;
#define MAXN (100000+5)
#define INF 0x3f3f3f3f
int n,k,arr[MAXN],mmin[MAXN];
int main() {
    while(~scanf("%d",&n)){
        mmin[0]=INF;
        for(int i=1;i<=n;i++)
            scanf("%d",&arr[i]);
        for(int i=1;i<=n;i++)
            mmin[i]=min(mmin[i-1],arr[i]);
 
        int res=0;
        for(int l=n,r=n;l>=1;l--){
            while(mmin[l]>arr[r])
                r--;
            res=max(res,r-l);
        }
        printf("%d\n",res);
    }
   return 0;
}


下面闲的*疼又优化了一下,指针直接跳到最小值位置,然后再往下遍历,当然了复杂度还是O(n)

#include <bits/stdc++.h>
using namespace std;
#define MAXN (100000+5)
#define INF 0x3f3f3f3f
int n,k,arr[MAXN],mmin[MAXN],mark[MAXN];
int main() {
    while(~scanf("%d",&n)){
        mmin[0]=INF,mark[0] = 0;
        for(int i=1;i<=n;i++)
            scanf("%d",&arr[i]);
        for(int i=1;i<=n;i++)
            if(mmin[i-1]<arr[i])
                mmin[i]=mmin[i-1] , mark[i] = mark[i-1];
            else
                mmin[i] = arr[i] , mark[i] = i;
 
        int res=0;
        for(int l=n,r=n;l>=1;){
            // cout<<"l="<<l<<' '<<" r="<<r<<" res="<<res<<endl;
            while( mmin[mark[l]] > arr[r] )
                r--;
            res=max(res,r-mark[l]);
            l=min(mark[l],--l);
            //cout<<"l="<<l<<' '<<" r="<<r<<" res="<<res<<endl<<endl;
        }
        printf("%d\n",res);
    }
   return 0;
}


整理的时候看到网上还有用最大值后缀+二分的,也还可以

这是一道排序可以过的题,也可以rmq+二分 最快的写法可以用单调栈做到O(n)

   我是求后面的最大值后缀,二分后缀;

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<queue>
#include<algorithm>
#include<stack>
#include<cstring>
#include<vector>
#include<list>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define pi (4*atan(1.0))
#define eps 1e-4
#define bug(x)  cout<<"bug"<<x<<endl;
const int N=1e5+10,M=1e6+10,inf=2147483647;
const ll INF=1e18+10,mod=2147493647;
 
int a[N],nex[N];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(nex,0,sizeof(nex));
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int j=n;j>=1;j--)
            nex[j]=max(a[j],nex[j+1]);
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            int s=i,e=n,pos=-1;
            while(s<=e)
            {
                int mid=(s+e)>>1;
                if(nex[mid]>=a[i])
                    pos=mid,s=mid+1;
                else e=mid-1;
            }
            ans=max(ans,pos-i);
        }
        printf("%d\n",ans);
    }
    return 0;
}



最开始做DP做疯了,DP瞎搞,没脑子,都快O(n^2)复杂度了都,还不如暴力,ORZ...
#include <bits/stdc++.h>
using namespace std;

#define MAXN (50000 + 10)

struct Node {
    int i, a, dp;
};

struct cmp{
    bool operator()(const Node &a,const Node &b) {
            return a.dp-b.dp>0;
    }
};

int main()
{
    int n, a;
    Node tmp;

    int ans;
    while (~scanf("%d", &n)) {
        set<Node, cmp> mySet;

        scanf("%d", &a);
        tmp.i=0,tmp.a = a,tmp.dp = 0;
        mySet.insert(tmp);
        ans = 0;
        for (int i = 1; i < n; ++i) {
            scanf("%d", &a);
            set<Node, cmp>::iterator it;

            for (it = mySet.begin(); it != mySet.end(); ++it)
                if (a >= (*it).a)   break;

            tmp.i = i,tmp.a = a;
            if (it == mySet.end())
                tmp.dp = 0;
            else
                tmp.dp = i - (*it).i + (*it).dp;

            if (tmp.dp > ans)  ans = tmp.dp;
            mySet.insert(tmp);
        }

        printf("%d\n", ans);
    }


    return 0;
}