2 2 1 10 3 2 5 4
Case #1: 0 Case #2: 1
最少改变几个数使这个序列变成单调递增序列,改变的数必须都是整数。
由于改变也要变成整数,所以并不是N减去一般的最长上升子序列的长度,因为会有这样的情况,1,2,2,2,3,最长上升子序列长度是3,但实际答案并不是2。于是要求的最长上升子序列要满足这样的条件dp[i]=max(dp[j]+1),j<i,a[j]<a[i],a[i]-a[j]>=i-j,这样能保证不在这个序列中的数都能改变成它们之间不相等的数。a[i]-a[j]>=i-j也就是a[i]-i>=a[j]-j,又因为i>j,所以这个条件满足了也必然满足a[j]<a[i]。因此问题变成了先构造a[i]-i的新数列,然后在这个数列中找一个单调不减序列,注意是单调不减而不是单调递增。
用nlogn的方法求就行,跟单调递增的求法相比有小改动,整体思路一样。
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long LL; const LL MAXN=100010; const LL MAXM=5010; const LL INF=0x3f3f3f3f; int T,N; int a[MAXN],dp[MAXN],s[MAXN]; int main(){ freopen("in.txt","r",stdin); scanf("%d",&T); int cas=0; while(T--){ scanf("%d",&N); for(int i=1;i<=N;i++){ scanf("%d",&a[i]); a[i]-=i; } memset(dp,0,sizeof(dp)); int top=1; s[1]=a[1]; dp[1]=1; for(int i=2;i<=N;i++){ if(a[i]>=s[top]){ s[++top]=a[i]; dp[i]=top; } else{ int pos=upper_bound(s+1,s+top+1,a[i])-s; s[pos]=a[i]; dp[i]=pos; } } int ans=0; for(int i=1;i<=N;i++) ans=max(ans,dp[i]); printf("Case #%d:\n%d\n",++cas,N-ans); } return 0; }