【upc】积木 | LIS、思维

问题 G: 积木

时间限制: 1 Sec  内存限制: 128 MB
提交 状态

题目描述

Mary在她的生日礼物中有一些积木。那些积木都是相同大小的立方体。每个积木上面都有一个数。Mary用他的所有积木垒了一个高塔。妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置。一个上面写有数i的积木的正确位置是这个塔从下往上数第i个位置。Mary决定从现有的高塔中移走一些,使得有最多的积木在正确的位置。请你告诉Mary她应该移走哪些积木。

输入

第一行为一个数n,表示高塔的初始高度。第二行包含n个数a1,a2,⋯,an,表示从下到上每个积木上面的数。(1≤n≤100000;1≤ai≤1000000)。

输出

输出最多有多少积木可以处在正确位置。

样例输入 Copy

5
1 1 2 5 4

样例输出 Copy

3

提示

Subtask #1 : n≤1
Subtask #2 : n≤500
Subtask #3 : n≤8000
Subtask #4: 无特殊限制。

题目大意:

中文题意

题目思路:

一直想着有一个比较好的思维LIS,找到了!

考虑当什么情况下可以通过删除使得ai == i

答案是:i>=ai的情况下(这个道理大家都懂)

那么对于i>=ai的位置来言,如果删除其前面一个位置那么(i-ai)就会-1

当i-ai ==0 时就满足要求了

此时会发现,按照i-ai从小到大排序后,剩下的合法元素(指i-ai>=0)的,如果删除的元素位置是i,由于k-a_k >= i-a_i,假设i在k的前面,此时删除就对后面没影响,因为假设删除完后i == ai(其实是一定可以的因为状态合法),由于k在i的后面所以,k-a_k 也同样的减少了 i-a_i ,但由于k-a_k >= i-a_i,所以影响可以忽略。

所以题解的思路也就产生了,按照i-a_i从小到大排序之后,找出最长的位置的递增序列即可

答案正确嘛?

答案并不是,因为样例就过不了:

把不合法的5排除后

0 1 1 1  
1 2 3 5

明显是4,但是是不可以同时存在两个1的,原因在于存在了相同的数字

所以转换一下,如果假设ai < aj,那么由于k-a_k > i - a_i,所以k一定大于i

所以如果求LIS,那么可以保证求出来的位置一定是递增,并且由于ai不相同,所以可行

Note:并不是充要条件

Code:

/*** keep hungry and calm CoolGuang!***/
#include 
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"<'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
ll dp[maxn];
struct node{
    ll a,b;
    bool friend operator<(node a,node b){
        if(a.a == b.a) return a.b=0) break;
    }
    int s = 0;
    for(int k=i;k<=n;k++){
        if(!s||save[k].b>st[s]) st[++s] = save[k].b;
        else{
            int pos = lower_bound(st+1,st+1+s,save[k].b)-st;
            st[pos] = save[k].b;
        }
    }
    printf("%d\n",s);
    return 0;
}
/**
**/
 
 

 

你可能感兴趣的:(LIS,LCS,upc经典题目及题解整理,思维锻炼)