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;
}