【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 <bits/stdc++.h>
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=2e18;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'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<b.b;
        return a.a < b.a;
    }
}save[maxn];
int st[maxn];
int main()
{
    read(n);
    for(int i=1;i<=n;i++){
        read(save[i].b);
        save[i].a = i -save[i].b;
    }
    sort(save+1,save+1+n);
    int i;
    for(i=1;i<=n;i++){
        if(save[i].a>=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;
}
/**
**/
 
 

 

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/107410558
UPC
lis