Codeforces 6E

来源:互联网 发布:淘客数据采集 编辑:程序博客网 时间:2024/04/29 05:19

题目大意:给定一个长度为n的序列和一个数k,求最大数与最小数的差小于等于k的子序列的最长长度,并输出有多少个,以及各自的左端点和右端点。

不得不说这道题目真是经典。刚开始看到这道题的时候,就觉得要用线段树做了,但始终不知道该怎么搞,我当时的想法很暴力,枚举l,r用线段树暴力判断是否满足,显然T得很惨。看题解有一句关键的话:“若[l,r]满足条件,则[l,r-1]也必然满足条件”。这句话说明了单调性,于是我便自然而然地想到了枚举l,二分查找一个最靠右的r。二分的框架出来了我们如何判断一个区间是否成立呢?如果使用线段树,总时间复杂度是O(nlog^2n)的,效率很低,但是800ms可过。还有一种就是Sparse-Table算法,也就是RMQ问题,用nlogn的时间预处理后O(1)查询,这样复杂度就优化到了O(nlogn)。注意预处理时n一定要倒着枚举!

%%%__debug大神。

#include<cstdio>#include<utility>#include<cstdlib>#include<cstring>#include<algorithm>#include<iostream>#include<vector>#define x first#define y secondconst int MAXN=100000+10;typedef std::pair<int,int> pii;int w[MAXN],max[MAXN][20],min[MAXN][20],n,k,cnt=0,lenans=0;std::vector<pii> ans;void Pre(){    for(int i=n;i>=1;i--)    {        for(int j=1;i+(1<<j)-1<=n;j++)        {            max[i][j]=std::max(max[i][j-1],max[i+(1<<(j-1))][j-1]);            min[i][j]=std::min(min[i][j-1],min[i+(1<<(j-1))][j-1]);        }    }}int findMaxMin(int l,int r){    int len=r-l+1,k=0,x=1;    while(x<=len)    {        k++;        x<<=1;    }k--;    return std::max(max[l][k],max[r-(1<<k)+1][k])-std::min(min[l][k],min[r-(1<<k)+1][k]);}int main(){    memset(min,0x3f3f3f3f,sizeof(min));    scanf("%d %d",&n,&k);    for(int i=1;i<=n;i++)        scanf("%d",&w[i]),max[i][0]=min[i][0]=w[i];    if(n==1)    {        printf("1 1\n%d %d\n",w[1],w[1]);        return 0;    }    Pre();    for(int i=1;i<=n;i++)    {        int l=i,r=n;        //if(l==r)continue;        int flag=findMaxMin(i,r);        if(flag<=k&&flag>=0){l=r;goto loop;}        while(l+1!=r)        {            int mid=(l+r)>>1;            if(findMaxMin(i,mid)<=k)                l=mid;            else                 r=mid;        }loop:   if(lenans<l-i+1)        {            lenans=l-i+1;            ans.clear();            ans.push_back(std::make_pair(i,l));        }        else if(lenans==l-i+1)            ans.push_back(std::make_pair(i,l));    }    printf("%d %d\n",lenans,ans.size());    for(int i=0;i<ans.size();i++)        printf("%d %d\n",ans[i].x,ans[i].y);}


0 0
原创粉丝点击