P2824 [HEOI2016/TJOI2016] 排序

P1136 迎接仪式

动态规划好题

状态设计:

我们认为z是1,j是0,产生贡献的是01对

我们用状态 \(f[i][j][k][0/1]\) 表示考虑到第 \(i\) 位,进行了 \(j\) 次将1变成0的操作和 \(k\) 次将0变成1的操作,操作过后第 \(i\) 位为 \(0/1\) 时的答案

状态转移:

然后我们就有方程:

\(a_i=1:\)

\( f[i][j][k][1]=max(f[i-1][j][k][0]+1,f[i-1][j][k][1]); \)

$ f[i][j][k][0]=max(f[i-1][j-1][k][0],f[i-1][j-1][k][1]);
$

\(a_i=0:\)

\( f[i][j][k][0]=max(f[i-1][j][k][0],f[i-1][j][k][1]); \)

\( f[i][j][k][1]=max(f[i-1][j][k-1][0]+1,f[i-1][j][k-1][1]); \)

当且仅当 \(j=k\) 时答案合法

然后这题就做完了

Code:

#include<bits/stdc++.h>
const int N=505;
const int K=105;
const int inf=1e9;
using namespace std;
int f[N][K][K][2],a[N];
int n,m,ans;
char c[N];
void init()
{
	for(int i=0;i<N;i++)for(int j=0;j<K;j++)for(int k=0;k<K;k++)f[i][j][k][0]=f[i][j][k][1]=-inf;
}
void work()
{
	init();
	cin>>n>>m;
	scanf("%s",c+1);
	f[0][0][0][1]=0;
	for(int i=1;i<=n;i++)
	{
		bool now = c[i]=='z';
		for(int j=0;j<=m;j++)
		{
			for(int k=0;k<=m;k++)
			{
				//01	
				//1:
				if(now)
				{
					f[i][j][k][1]=max(f[i-1][j][k][0]+1,f[i-1][j][k][1]);
					if(j)f[i][j][k][0]=max(f[i-1][j-1][k][0],f[i-1][j-1][k][1]);
				}
				//0:
				else
				{
					f[i][j][k][0]=max(f[i-1][j][k][0],f[i-1][j][k][1]);
					if(k)f[i][j][k][1]=max(f[i-1][j][k-1][0]+1,f[i-1][j][k-1][1]);
				}
			}
		}
	}
	for(int i=1;i<=m;i++)ans=max({ans,f[n][i][i][0],f[n][i][i][1]});
	printf("%d",ans);
}
int main()
{
	//freopen("welcome.in","r",stdin);
	//freopen("welcome.out","w",stdout);
	work();
}
posted @ 2024-12-06 12:09  liuboom  阅读(10)  评论(0)    收藏  举报