CF180E Cubes 题解

CF180E Cubes 题解

洛谷。

CF。

首先把相邻的颜色相同的元素看成一个块,那么操作就是删除块之间的东西把若干个块拼在一起。

观察一下不难发现删除的元素一定是连续的,因为如果不连续那么只有一段区间是有用的,另一端区间就是白费了。

然后考虑枚举每个块,从第 \(i\) 个块的后面一个元素开始删。显然删的东西越多越好,就尽量把 \(k\) 次机会全用完。

于是就可以写出暴力的代码了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ljl;
#define pb push_back
const int N=2e5+5,M=1e5+5;
int n,m,k,a[N],tot,ans;
vector<int> col[M];
struct NODE{
	int l,r,c,p;
}node[N];
bool check()
{
	for(int i=2;i<=n;++i)
		if(a[i]!=a[1])return 0;
	return 1;
}
int main(){
	ios::sync_with_stdio(0);
	cin>>n>>m>>k;
	for(int i=1;i<=n;++i)cin>>a[i];
	if(check()){cout<<n<<'\n';return 0;}
	for(int i=1;i<=n;++i)
	{
		node[++tot].c=a[i];
		node[tot].l=i;int j=i;
		while(j<=n&&a[j]==a[i])++j;
		node[tot].r=j-1;i=j-1;
		ans=max(ans,node[tot].r-node[tot].l+1);
		col[a[i]].pb(tot);
		node[tot].p=(int)col[a[i]].size()-1;
	}
	for(int i=1,s;i<tot;++i)//在第i块后边开始删除 
	{
		s=0;
		int T=k,j=node[i].p,ls=(int)col[node[i].c].size();
		for(;j<ls;++j)
		{
			int I=col[node[i].c][j],nxt=col[node[i].c][j+1];
			s+=node[I].r-node[I].l+1;
			if(j==ls-1)break;
			T-=(node[nxt].l-1-node[I].r);
			if(T<0)break;
		}ans=max(ans,s);
	}
	cout<<ans<<'\n';
	return 0;
}

然后交到 CF 上就会 TLE on test 45

然而这题学长放 NOIP 模拟赛里了,结果不知道为啥给我 A 了……

然后考虑优化。

考虑前缀和,设 \(s_{i,j}\) 表示颜色为 \(i\),考虑到第 \(j\) 个块的两块之间的距离和。那么就是找到最后一个小于等于 \(k-s_{c_i,p-1}\) 的位置。

其中 \(c_i\) 表示块 \(i\) 的颜色,\(p\) 为第 \(i\) 块在所有颜色为 \(c_i\) 的块中的排名。

这显然可以用二分做。

然后就做完了。

Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ljl;
#define pb push_back
const int N=2e5+5,M=1e5+5;
ljl n,m,k,a[N],tot,ans;
vector<ljl> col[M];
vector<ljl> sum[M],s2[M];
struct NODE{
	ljl l,r,c,p;
}node[N];
bool check()
{
	for(int i=2;i<=n;++i)
		if(a[i]!=a[1])return 0;
	return 1;
}
ljl lwb(int cl,ljl L,ljl R,ljl c)//从sum[cl] [l~r] 中找到最后一个 <=c 的 
{
	int l=L,r=R,mid,ans=l;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(sum[cl][mid]<=c)ans=mid,l=mid+1;
		else r=mid-1;
	}return ans;
}
int main(){
	ios::sync_with_stdio(0);
	cin>>n>>m>>k;
	for(int i=1;i<=n;++i)cin>>a[i];
	if(check()){cout<<n<<'\n';return 0;}
	for(int i=1;i<=n;++i)
	{
		node[++tot].c=a[i];
		node[tot].l=i;int j=i;
		while(j<=n&&a[j]==a[i])++j;
		node[tot].r=j-1;i=j-1;
		ans=max(ans,node[tot].r-node[tot].l+1);
		col[a[i]].pb(tot);
		node[tot].p=(int)col[a[i]].size()-1;
	}
	for(int i=1;i<=m;++i)
	{
		ljl ls=(ljl)col[i].size();
		if(!ls)continue;
		for(int j=0;j<=ls;++j)sum[i].pb(0);
		sum[i][1]=0;int lst=node[col[i][0]].r;
		for(int j=1;j<ls;++j)
		{
			int l=node[col[i][j]].l,r=node[col[i][j]].r;
			sum[i][j+1]=sum[i][j]+(l-1-lst);
			lst=r;
		}
	}
	for(int i=1;i<=m;++i)
	{
		int ls=(int)col[i].size();
		if(!ls)continue;
		for(int j=0;j<=ls;++j)s2[i].pb(0);
		s2[i][0]=node[col[i][0]].r-node[col[i][0]].l+1;
		for(int j=1;j<ls;++j)s2[i][j]=s2[i][j-1]+node[col[i][j]].r-node[col[i][j]].l+1;
	}
	for(int i=1;i<tot;++i)//在第i块后边开始删除 
	{
		ljl s=0;int cl=node[i].c;
		ljl j=node[i].p+1,ls=(int)col[cl].size();
		ljl c=lwb(cl,j,ls,k+sum[cl][j]);
//		for(int p=j-1;p<c;++p)s+=(node[col[cl][p]].r-node[col[cl][p]].l+1);
		if(j>=2)
			s=s2[cl][c-1]-s2[cl][j-2];
		else s=s2[cl][c-1];
		ans=max(ans,s);
	}
	cout<<ans<<'\n';
	return 0;
}

AC link.

posted @ 2026-08-18 22:55  Atserckcn  阅读(8)  评论(0)    收藏  举报