P3902 递增

尝试转化成已知的问题 : 如果原问题是非严格单调递增,则直接求出 L I S LIS LIS的⻓度,从n中减去就行了。

注意到这里的 a i ai ai都是整数, a i < a i + 1 a_i < a_{i+1} ai<ai+1 相当于 a i + 1 a i + 1 a_i + 1 ≤a_{i+1} ai+1ai+1
于是
a 1 < a 2 < < a n 1 < a n a_1 < a_2 < ··· < a_{n−1} < a_n a1<a2<<an1<an
就相当于
a 1 + ( n 1 ) a 2 + ( n 2 ) a n 1 + 1 a n a_1 + (n−1) ≤a_2 + (n−2) ≤···≤a_n−1 + 1 ≤a_n a1+(n1)a2+(n2)an1+1an

将原数组进行预处理,就可以转化成 L I S LIS LIS问题了。
这里直接转换成LIS问题以后就直接用LIS问题的转移方程

f i = m a x { f j } + 1 f_i=max \{f_j​ \} +1 fi=max{fj}+1,其中j < i

用树状数组维护 m a x max max值,时间复杂度降到 O ( n l o g n ) O(nlogn) O(nlogn)

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<math.h>
#include<vector>
#define ls (p<<1)
#define rs (p<<1|1)
#define mid (l+r)/2
#define over(i,s,t) for(register long long i=s;i<=t;++i)
#define lver(i,t,s) for(register long long i=t;i>=s;--i)
//#define int __int128
using namespace std;
typedef long long ll;//全用ll可能会MLE或者直接WA,试着改成int看会不会A
const ll N=200007;
const ll INF=1e10+9;
const ll mod=2147483647;
const double EPS=1e-10;//-10次方约等于趋近为0
const double Pi=3.1415926535897;

ll n,m,a[N],tree[N];

inline void update(ll k,ll x)
{
    while(k<N)
    {
        tree[k]=max(tree[k],x);
        k+=k&(-k);
    }
}
inline ll query(ll k)
{
    ll res=0;
    while(k)
    {
        res=max(res,tree[k]);
        k-=k&(-k);
    }
    return res;
}
int main()
{
    scanf("%lld",&n);
    vector<ll>v;
    over(i,1,n)
    {
        scanf("%lld",&a[i]);
        a[i]+=n-i;
        v.push_back(a[i]);
    }
    sort(v.begin(),v.end());
    over(i,1,n)
        a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;
    over(i,1,n)//从前往后走,先query前面的更新后面最大值
        update(a[i],query(a[i])+1);

    printf("%lld\n",n-query(n+1));//树状数组不能从0开始,必须从1开始
}