码迷,mamicode.com
首页 > 其他好文 > 详细

#305 (div.2) D. Mike and Feet

时间:2015-05-28 14:08:34      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:codeforces   思维题   扫描法   等价转换   

1.题目描述:点击打开链接

2.解题思路:本题是一道很好的思维题。看好多人用单调栈解决的。这里介绍另一种解决方法:首先,根据题意描述,我们知道连续序列的最小值是关键,如果任意给出一个连续序列,找它的最小值,反而不太方便;但是换个角度,如果知道最小值,求以它为最小值的最大的连续序列!这就简单的多了。即找出这个元素向左可以延伸多远,向右能延伸多远,然后就能求出最大连续序列的长度了。

现在的问题是,如何快速找到每个元素向右能延伸的最远距离,向左能够延伸的最远距离?这里我们尝试利用扫描法解决。用L[i]表示第i个元素向左能够延伸的最远的下标,R[i]表示向右的最远下标。初始化的时候L[i]=R[i]=i。接下来我们利用不等式关系来寻找最远下标。

假设枚举到了第i个元素val[i],那么它左边的元素就是val[L[i]-1](因为初始化的时候L[i]=i,等价于val[i-1]),如果有val[L[i]-1]>=val[i],那么L[i]就是元素val[L[i]-1]的最左边的下标L[L[i]-1],即L[i]=L[L[i]-1],接下来继续判断是否有val[L[i]-1]>=val[i]成立,直到不满足这个关系式为止。这样我们就找到了L[i]。同理也可找到R[i],那么val[i]所在的最长的连续子序列长度就是R[i]-L[i]+1。

最后,我们将(len,val)看做一个二元组,对len排序,那么对于每一个len,只需要更新所有的d<=len的答案即可(d表示长度)。

3.代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
typedef pair<long long,long long> PL;

#define me(s) memset(s,0,sizeof(s))
#define For(i,n) for(int i=0;i<(n);i++)
#define pb push_back
#define sz size
#define clr clear

#define N 200000+6
struct Node
{
    int len,num;
}a[N];
int T,t,n,m;
int L[N],R[N];
int val[N],ans[N];
bool cmp(Node a,Node b)
{
    return a.num>b.num;
}
int main()
{
   // freopen("t.txt","r",stdin);
    int len;
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
         {
             scanf("%d",&val[i]);
             L[i]=R[i]=i;
         }
         for(int i=1;i<=n;i++)
            while(val[L[i]-1]>=val[i])//更新最左边的下标
            L[i]=L[L[i]-1];
         for(int i=n;i>=1;i--)
            while(val[R[i]+1]>=val[i])//更新最右边的下标
            R[i]=R[R[i]+1];
         for(int i=1;i<=n;i++)
         {
             a[i].len=R[i]-L[i]+1;//计算出最长连续子串的长度
             a[i].num=val[i];
         }
         sort(a+1,a+n+1,cmp);//对长度排序
         ans[0]=1e9+7;//a[0]要置为一个比所有元素都大的值,这样保证后面的while循环一定会停止
         for(int i=1;i<=n;i++)
         {
             len=a[i].len;
             while(ans[len]<a[i].num)//更新所有长度不超过len的答案
             {
                 ans[len]=a[i].num;
                 len--;
             }
         }
         for(int i=1;i<=n;i++)
            printf("%d%c",ans[i],i==n?'\n':' ');
    }
    return 0;
}

#305 (div.2) D. Mike and Feet

标签:codeforces   思维题   扫描法   等价转换   

原文地址:http://blog.csdn.net/u014800748/article/details/46121267

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!