[2020.12.3周四]最长上升子序列LIS
题意:给定一个序列a[],问至少需要修改多少个数,才能使a[]严格递增。
题解:ans=n-LIS
算法:这个算法dp写需要O(n^2),dp到每个数的最长上升子序列长度,(dp[i]=max_{j<i,a[j]<a[i]}(dp[j]))
有点偏序的意思,其实可以写离散后写树状数组二维偏序的,但太麻烦了。
其实可以这样dp(如下程序),dp[i]=长度为i+1的序列的尾部最小数
如果当前数比dp所有数大,就把他加入dp数组
否则,它必然可以把一个dp长度尾部的数替换掉;
tag:最长上升子序列
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
const int inf =0x3f3f3f3f;
int a[maxn];
int main()
{
int T;scanf("%d",&T);int t=0;
while(T--)
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",a+i),a[i]-=i;//把严格递增转成非严格递增
vector<int>dp;
for(int i=1;i<=n;i++)
{
auto pos=upper_bound(dp.begin(),dp.end(),a[i]);
if(pos==dp.end()) dp.push_back(a[i]);
else *pos=a[i];
}
printf("Case #%d:
",++t);
printf("%d
",n-(int)dp.size());
}
}
题意:给定一个序列a[],问至少需要修改多少个数,才能使a[]严格递增,其中有k个数是不可以修改的。
题解:遇上题同理,区别在于k个不能修改的数,将a[] 分成k+1段,分段求LIS
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+100;
const int inf=0x3f3f3f3f;
ll a[maxn],b[maxn];
int main()
{
int n,k;
cin>>n>>k;bool flag=true;
for(int i=1;i<=n;i++)cin>>a[i],a[i]-=i;//a[i]>=0,非严格递增
for(int i=1;i<=k;i++) cin>>b[i];
b[0]=0;b[k+1]=n+1;a[0]=-1e9-2;a[n+1]=1e9+10;
int ans=0;
for(int i=0;i<=k;i++)
{
int l=b[i],r=b[i+1];
if(a[l]>a[r]) {
cout<<"-1"<<endl;return 0;
}
vector<int>dp;
for(int j=l+1;j<r;j++)//求一段a[],值在[a[l],a[r]]内的最长子序列
{
if(a[l]<=a[j]&&a[j]<=a[r])
{
auto pos=upper_bound(dp.begin(),dp.end(),a[j]);
if(pos==dp.end())dp.push_back(a[j]);
else *pos=a[j];
}
}
ans+=(r-l-1)-(int)dp.size();
}
cout<<ans<<endl;
}
题意:洛谷模板题。给南北两岸友好城市的坐标,问最多有多少对城市两两不相交。
题解:排序一边城市,另一边城市求一个LIS。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+100;
const int inf =0x3f3f3f3f;
pair<int,int> a[maxn];
int s[maxn];
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&a[i].first,&a[i].second);
sort(a+1,a+1+n);
vector<int>dp;
for(int i=1;i<=n;i++)
{
auto pos=upper_bound(dp.begin(),dp.end(),a[i].second);
if(pos==dp.end())dp.push_back(a[i].second);
else *pos=a[i].second;
}
printf("%d",(int)dp.size());
}
拓展
(1)LIS的期望