Codeforces Round #650 (Div. 3)
F1. Flying Sort (Easy Version)
题意:
给定长度为n的序列a,保证序列中的数两两不同
有两种操作:
1.选择序列中的一个数,将他移动到序列开头
2.选择序列中的一个数,将他移动到序列结尾
现在你可以进行无限次操作,问最少使用多少次操作能够使得序列递增
数据范围:n<=3e4,a(i)<=1e9
解法:
最优情况下每个数最多操作一次,
将问题转化为计算:n - 不需要操作的数量,求最大不需要操作数量即可
因为每次操作只能将一个数移到前面和后面,而不能移到中间,
所以最大不需要操作数量就是满足数字连续的最长子序列长度,
例如2 3 1 5 4,数字连续的最长子序列是2 3 4,长度为3,那么答案为5-3=2
完整解题步骤:
因为a(i)很大,所以先离散化
令d[i]表示以i为结尾的最大长度,那么转移方程:d[a[i]]=d[a[i]-1]+1
设d[i]的最大值为ma,则答案为n-ma
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=3e3+5;
int a[maxm];
int b[maxm];
int d[maxm];
signed main(){
int T;cin>>T;
while(T--){
int n;cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+1+n);
for(int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+1+n,a[i])-b;
}
for(int i=1;i<=n;i++){
d[i]=0;
}
int ma=0;
for(int i=1;i<=n;i++){
d[a[i]]=d[a[i]-1]+1;
ma=max(ma,d[a[i]]);
}
cout<<n-ma<<endl;
}
return 0;
}
F2. Flying Sort (Hard Version)
题意:
在F1的基础上,n的范围由3e4变为2e5,且序列a中的元素可以相同
解法:
基本思路还是一样,求最大不操作数量
但是现在数字会重复,且每次操作只能将一个数移到前面和后面,而不能移到中间,
所以如果我们选择的子序列的值域为[x,y],那么[x+1,y-1]的所有数都必须被选定,一个都不能少
令d[i]表示以a[i]为结尾的最大长度
last[a[i]]表示a[i]上一次出现位置
tot[a[i]]表示a[i]的总数量
cnt[a[i]]表示当前遇到的a[i]总数量
fir[a[i]]表示a[i]出现的第一个位置
转移:
d[i]=1;
d[i]=d[last[a[i]]+1;
d[i]=cnt[a[i]-1]+1;
if(cnt[a[i]-1]==tot[a[i]-1]){
d[i]=d[fir[a[i]-1]]+tot[a[i]-1];
}
对所有取max
ps:
d[i]=d[last[a[i]-1]]+1;是不允许的
因为只有a[i]-1 全部出现在中间才能这样
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=2e5+5;
int a[maxm];
int b[maxm];
int d[maxm];
int tot[maxm];
int cnt[maxm];
int fir[maxm];
int last[maxm];
signed main(){
int T;cin>>T;
while(T--){
int n;cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+1+n);
int num=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+1+num,a[i])-b;
}
for(int i=1;i<=num;i++){
tot[i]=cnt[i]=fir[i]=last[i]=0;
}
for(int i=1;i<=n;i++){
tot[a[i]]++;
}
int ma=0;
for(int i=1;i<=n;i++){
//
d[i]=1;
d[i]=max(d[i],d[last[a[i]]]+1);//从上一个a[i]转移
d[i]=max(d[i],cnt[a[i]-1]+1);//前面接已有的全部a[i]-1
//不能从d[last[a[i]-1]]转移是因为必须a[i]-1全部出现在中间
if(cnt[a[i]-1]==tot[a[i]-1]){//如果a[i]-1全部出现,则可以从第一个a[i]-1转移
d[i]=max(d[i],d[fir[a[i]-1]]+tot[a[i]-1]-1+1);
}
//
if(!fir[a[i]]){
fir[a[i]]=i;
}
cnt[a[i]]++;
last[a[i]]=i;
ma=max(ma,d[i]);
}
cout<<n-ma<<endl;
}
return 0;
}