「NOIP模拟赛」 迎接仪式
「问题描述」
LHX教主要来X市指导OI学习工作了。为了迎接教主,在一条道路旁,一群Orz教主er穿着文化衫站在道路两旁迎接教主,每件文化衫上都印着大字。一旁的Orzer依次摆出“欢迎欢迎欢迎欢迎……”的大字,但是领队突然发现,另一旁穿着“教”和“主”字文化衫的Orzer却不太和谐。
为了简单描述这个不和谐的队列,我们用“j”替代“教”,“z”替代“主”。而一个“j”与“z”组成的序列则可以描述当前的队列。为了让教主看得尽量舒服,你必须调整队列,使得“jz”子串尽量多。每次调整你可以交换任意位置上的两个人,也就是序列中任意位置上的两个字母。而因为教主马上就来了,时间仅够最多作K次调整(当然可以调整不满K次),所以这个问题交给了你。
「输入格式」
输入文件welcome.in的第1行包含2个正整数N与K,表示了序列长度与最多交换次数。
第2行包含了一个长度为N的字符串,字符串仅由字母“j”与字母“z”组成,描述了这个序列。
「输出格式」
输出文件welcome.out仅包括一个非负整数,为调整最多K次后最后最多能出现多少个“jz”子串。
「样例输入」
5 2
zzzjj
「样例输出」
2
「样例说明」
第1次交换位置1上的z和位置4上的j,变为jzzzj;
第2次交换位置4上的z和位置5上的j,变为jzzjz。
最后的串有2个“jz”子串。
「数据规模」
对于10%的数据,有N≤10;
对于30%的数据,有K≤10;
对于40%的数据,有N≤50;
对于100%的数据,有N≤500,K≤100
这是一道DP题,本题的难点在于状态的确定,由于调整是任意的,很难划分状态,我们略微修改一下调整的形式:把一次’j’和’z’交换看做两次变换:’j’->’z’;’z’->’j’ (zz交换和jj交换是没有意义的,不作考虑);于是最多’j’->’z’ ‘z’->’j’各K次. F[i,j,k]:=F[i-2,j-x,k-x]+1;
If A[i-1]=j then x=0 else x=1
If A[i]=z then y=0 else y=1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #define inf 1000000000 using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int t1,t2; int n,K,ans; char a[505]; int f[505][105][105]; void dp() { for(int i=2;i<=n;i++) for(int x=0;x<=K;x++) for(int y=0;y<=K;y++) { f[i][x][y]=f[i-1][x][y]; if(a[i]=='j')t1=1;else t1=0; if(a[i-1]=='z')t2=1;else t2=0; if(x>=t1&&y>=t2)f[i][x][y]=max(f[i-1][x][y],f[i-2][x-t1][y-t2]+1); if(x==y)ans=max(ans,f[i][x][y]); } } int main() { n=read();K=read(); scanf("%s",a+1); dp(); t1=t2=0; for(int i=1;i<=n;i++) if(a[i]=='j')t1++; else t2++; ans=min(ans,min(t1,t2)); printf("%d\n",ans); return 0; } |