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

浙公网安备 33010602011771号