P1136 迎接仪式

本题只有必要对j和z进行最多m次交换,也就是重新编排序列,通过记录跟原序列有何差别来保证m次交换。
可以维护\(f[i][k_1][k_2][0/1]\)表示在第1到i位中把\(k_1\)个'j'换成了'z',\(k_2\)个'z'换成了'j',最后一位是'j'还是'z'(为了转移时计数)。
这时总共进行了\(k_1+k_2\)次操作,第1~i位中的'j'个数也可求。
分别讨论第i位时'j'还是'z'的情况,确定交换的种类,枚举\(k_1k_2\)即可,如果该位时'z',那么当前一位为'j'时就可以+1。
但是具体实现时候需要滚动数组滚掉第一维保证空间。
转移需要3层循环嵌套,时间复杂度\(O(nm^2)\)

代码 :

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[505];
int s[505];
int num;
int f[105][105][2];
int main() {
//	freopen("P1136.in","r",stdin);
//	freopen("P1136.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) {
		char c; cin>>c;
		s[i]=s[i-1];
		if(c=='j') a[i]=0;
		else a[i]=1,num++,s[i]++;
	}
	for(int k1=m;k1>=0;k1--) {
		for(int k2=m;k2>=0;k2--) {
			f[k1][k2][0]=f[k1][k2][1]=-1e9;
		}
	}
	f[0][0][1]=0;
	int ans=0;
	for(int i=1;i<=n;i++) {
		for(int k1=m;k1>=0;k1--) {
			for(int k2=m;k2>=0;k2--) {
				int j=s[i]+k1-k2;
				if(j>num) continue;
				int add1=0,add2=0;
				if(!a[i]) add1=1; if(a[i]) add2=1;
				int num1=-1e9,num2=-1e9;
				if(j && k1>=add1) num1=max(f[k1][k2][1],max(f[k1-add1][k2][1],f[k1-add1][k2][0]+1));
				if(k2>=add2) num2=max(f[k1][k2][0],max(f[k1][k2-add2][0],f[k1][k2-add2][1]));
				f[k1][k2][1]=num1,f[k1][k2][0]=num2;
				if(k1==k2) ans=max(ans,max(f[k1][k2][0],f[k1][k2][1]));
//				printf("%d %d %d %d 0 %d\n",i,j,k1,k2,f[k1][k2][0]);
//				printf("%d %d %d %d 1 %d\n",i,j,k1,k2,f[k1][k2][1]);
			}
		}
	}
	printf("%d",ans);
	return 0;
}
posted @ 2024-02-17 19:47  Ian8877  阅读(12)  评论(0)    收藏  举报