CF1454C Sequence Transformation 题解
我们先来看题
这道题我们首先就可以想出一个思路:我们枚举从1到
但如果这么做的话,我们不难发现一个问题:时间复杂度是
我们可以看到,所谓
为了解决这个问题,我们来复习一下小学奥数——植树问题!
问题:已知街道上有
(1)假设街两头都栽树,这条路长几米?
(2)假设街两头都不栽树,这条路长几米?
(3)假设街两头只有一头栽树,这条路长几米?
答案:
(1):
(2):
(3):
由此我们可以看出,当一段顶头时,就有
这道题也是如此,我们求要删几次,就是要求区间数,用上面的方法即可。
所以第一步,我们要离线处理每一个数字存在的次数。
我们这个时候会发现一个问题:
举个例子:1 2 2 3 2 1
我们可以发现,在第一个2和第二个2之间,是没有东西的,理论上来说,它俩之间也要删一次,但它俩之间都没东西了,删什么删?
所以我们在处理之前,还要合并相同且相邻的数字: 这样就正常多了。
第二步就是运用我们上述所说的东西,将求解由
接下来是你们最开心的代码时刻:
#include<iostream>
#include<cstdio>
using namespace std;
int read(){ //快读
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
int ai[200005]; //未去重的数组
int a[200005]; //去重的数组
int tong[200005];
void cf(){
int n=read();
int cnt=0;
for(int i=1;i<=n;i++){ //去重
ai[i]=read();
if(ai[i]!=a[cnt]){
cnt++;
a[cnt]=ai[i];
}
}
for(int i=1;i<=cnt;i++) //利用桶排的思想记录“树”的数量
tong[a[i]]++;
int ansi=200004;//将最优解初始化为一个无穷大的数
//下面是更新最优解
for(int i=2;i<=n-1;i++)
if(tong[ansi]>tong[a[i]]&&tong[a[i]]!=0) ansi=a[i];
if(tong[ansi]>=tong[a[1]]&&tong[a[1]]!=0) ansi=a[1];
if(tong[ansi]>=tong[a[cnt]]&&tong[a[cnt]]!=0) ansi=a[cnt];
if(a[1]==a[cnt]&&tong[ansi]>=tong[a[1]]-1&&tong[a[1]]!=0) ansi=a[1];
//上面是更新最优解
if(cnt==1||cnt==2) printf("%d\n",cnt-1); //特判
else{
if(ai[1]==ansi&&ai[n]==ansi) printf("%d\n",tong[ansi]-1); //当两侧都是最前或最后时,答案是树的数量-1
else{
if(ai[1]==ansi||ai[n]==ansi) printf("%d\n",tong[ansi]);//当两侧有一侧是最前或最后时,答案就是树的数量
else printf("%d\n",tong[ansi]+1); // 当两侧都不是最前或最后是,答案就是树的数量+1
}
}
for(int i=1;i<=n;i++){ //初始化
ai[i]=0;
a[i]=0;
tong[i]=0;
}
return;
}
int main(){
int t=read(); //t组数据
tong[200004]=0x3f3f3f; //见32行
for(int i=1;i<=t;i++)
cf();
return 0;
}
接下来的东西与学术没有关系,大佬可以跳过,直接点赞走人;想摸鱼的可以看完剩下部分,再点赞走人。
传送门