Codeforces Round 893 (Div. 2) D

链接

第一个想法:\(O(n^2)\)可过,很明显,我可以直接统计出来每一个位置作为中心,向两边扩展最多能得到的多少个连续的1。

这个想法是不成熟的,但是我甚至开始写了。哎。然后写了140行,发现寄了,思路太复杂,完全用不了。

这里就引出了一个事情:太复杂的思路其实不能算是思路,因为表达是不可能这么复杂的。这是一定要纳入出题人的考虑之中的。

所以当想到一个可行,但是实现想想都巨复杂,就不要当成是训练代码能力了。一个简单而优美的实现思路是非常值得学习的。

对于这题,其实就是在锻炼实现思路的简洁。我觉得这题对我是可以说到2400左右难度的,但是思路确实一点都不难想。\(O(n^2)\)的限制实在是特别宽裕。你不管怎么样,随便统计答案都可以。

而这个实现思路在我看来是真的非常优秀的,简洁,优美,我看到他代码的思路的时候就感觉很喜欢。

对于这题,我们其实可以直接钦定一段,把这段全部都变成1,然后再计算两边最长的。而我们把这段全部变成1所花的代价是固定的,也就是我们不需要枚举k,可以直接通过枚举这段的左右端点来计算答案。

这也就是我们的实现思路了。
我也想能想出来这种思路。。这个和思维习惯相关吧,这个题目的要求毕竟太松,想要准确的想到这个好写的思路,还是有点碰运气的。
但是我觉得总体上可以得到一个办法,就是先去固定难以描述的,或者是先找到一个,把这个固定下来能够简单的描述尽可能多的东西的东西。这题里面,直接固定l,r,就很方便,然后再根据这个需求去算其他东西。
但是,要想到这思路,那我可能想做法的时候就要想到了。但是我现在还是跟习惯从左到右的dp。
以后想的时候可以试试看,如果我直接把左右端点固定下来,会不会很方便?

只能这样了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
	char c=getchar();ll a=0,b=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
ll n,k,pre[3001][3001],f[3001],sub[3001][3001],ans[3001];
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ll T=read();
	while(T--)
	{
		n=read(),k=read();
		string s;
		cin>>s;
//		memset(sub,0,sizeof(sub));
//		memset(pre,0,sizeof(pre));
//		memset(ans,0,sizeof(ans));
//		memset(f,0,sizeof(f));
		for(ll i=0;i<=n;i++)
		{
			ans[i]=f[i]=-1e9;
			for(ll j=0;j<=n;j++)
			{
				pre[i][j]=sub[i][j]=0;
			}
		}
		for(ll l=0;l<n;l++)
		{
			ll cnt1=0;
			for(ll r=l+1;r<=n;r++)
			{
				if(s[r-1]=='1')cnt1++;
				pre[r][cnt1]=max(pre[r][cnt1],r-l);
				sub[l][cnt1]=max(sub[l][cnt1],r-l);
			}
		}
		for(ll r=0;r<=n;r++)
		{
			for(ll j=0;j<=n;j++)
			{
				if(r!=0)pre[r][j]=max(pre[r][j],pre[r-1][j]);
				if(j!=0)pre[r][j]=max(pre[r][j],pre[r][j-1]);
			}
		}
		for(ll l=n;l>=0;l--)
		{
			for(ll j=0;j<=n;j++)
			{
				if(l!=n)sub[l][j]=max(sub[l][j],sub[l+1][j]);
				if(j!=0)sub[l][j]=max(sub[l][j],sub[l][j-1]);
			}
		}
		for(ll l=0;l<n;l++)
		{
			ll cnt0=0;
			for(ll r=l;r<=n;r++)
			{
				if(r!=l&&s[r-1]=='0')cnt0++;
				if(cnt0>k)break;
				f[r-l]=max(f[r-l],max(sub[r][k-cnt0],pre[l][k-cnt0]));
			}
		}
		for(ll i=0;i<=n;i++)
		{
			for(ll a=1;a<=n;a++)
			{
				ans[a]=max(ans[a],f[i]*a+i);
			}
		}
//		cout<<f[1]<<endl;
		for(ll i=1;i<=n;i++)
		{
			cout<<ans[i]<<' ';
		}
		cout<<endl;
	}
	return 0;
}

posted @ 2024-04-10 22:37  HL_ZZP  阅读(2)  评论(0编辑  收藏  举报