読者です 読者をやめる 読者になる 読者になる

メモ

yukicoderで遊んでいる競プロゆるふわ勢

yukicoder No.291 黒い文字列

問題はこちら
No.291 黒い文字列 - yukicoder

DPの状態遷移を考えるのに2時間くらいかかってしまった……

dp[i][a][b][c][d]=(i文字目まで見て、Kがa個、内KUがb個、内KURがc個、内KUROがd個あるときのKUROIの内数) として配るDPを考える
K,U,R,O,Iの各文字がきたらそれを使わない理由はないので

(i+1)文字目が
Kのときdp[i+1][a+1][b][c][d]=dp[i][a][b][c][d]
Uのときdp[i+1][a][b+1][c][d]=dp[i][a][b][c][d]
Rのときdp[i+1][a][b][c+1][d]=dp[i][a][b][c][d]
Oのときdp[i+1][a][b][c][d+1]=dp[i][a][b][c][d]
Iのときdp[i+1][a][b][c][d]  =min(dp[i][a][b][c][d]+1,d)
?のとき上記全て(ただしこのときは同じ箇所に2回以上配る可能性があるので、単なる代入ではなくもとの値とmaxをとる必要がある)
いずれでもない時
    dp[i+1][a][b][c][d]  =dp[i][a][b][c][d]

というように更新していける。
配り先は(Kの個数)>(KUの個数)となるようなものも含まれてしまうが、配り元の方で気をつけておけば問題ない
最大値が更新されるのはIまたは?がきた時だけであることに注意
dpの初期値は-1とかにしておかなければならないが面倒なのでさぼって、実際の値+1を保存することにする
(値が0のところからは配り始めない)

一見すると状態数が|S|^5、a≧b≧c≧dを考慮しても|S|^5/24だが、完成するKUROI文字列の個数は高々|S|/5なので、K,KU,KUR,KUROの完成数もそれを上限として打ち切って良い。
すると|S|^5/625=1.6*10^7となり通る

#define f(i,e)for(i=0;i<=e;i++)
#define max(p,q)(p<(q)?p=q:p)
char s[110];
dp[110][22][22][22][22];
i,a,b,c,d,t,ans;
int main(){
	*****dp=1;
	for(gets(s);s[i];i++)f(a,20)f(b,a)f(c,b)f(d,c)if(t=dp[i][a][b][c][d]){
		if(s[i]=='K'||s[i]=='?')max(dp[i+1][a+1][b][c][d],t);
		if(s[i]=='U'||s[i]=='?')max(dp[i+1][a][b+1][c][d],t);
		if(s[i]=='R'||s[i]=='?')max(dp[i+1][a][b][c+1][d],t);
		if(s[i]=='O'||s[i]=='?')max(dp[i+1][a][b][c][d+1],t);
		if(s[i]=='I'||s[i]=='?')max(ans,max(dp[i+1][a][b][c][d],d<t?d:t+1));
		max(dp[i+1][a][b][c][d],t);
	}
	printf("%d",ans-1);
	return 0;
}

さて、これを縮める。
まずdp[ ][ ][ ][ ][ ]とs[i]==' 'が目につくのでこれをどうにかしたい。
tをポインタにすればt=&dp[ ][ ][ ][ ][ ]とかでいい感じにできそう。
char*を用意してs[i]を消し、s[i]=='?'は適当な文字でおく。

#define f(i,e)for(i=e+1;i--;)
#define m(p,q)(p<(q)?p=q:p)
char s[110],*p=s;
q[22][22][22][22][102];
i,a,b,c,d,x,*t;
main(S){
	*****q=1;
	for(gets(s);*p;p++,i++)f(a,20)f(b,a)f(c,b)f(d,c)
		*(t=&q[a][b][c][d][i])?
			x=*p-63,
			*p-75&&x||m(t[1086097],*t),
			*p-85&&x||m(t[49369],*t),
			*p-82&&x||m(t[2245],*t),
			*p-79&&x||m(t[103],*t),
			*p-73&&x||m(S,m(t[1],d<*t?d:*t+1)),
			m(t[1],*t)
		:0;
	i=!printf("%d",S-1);
}

iが要らなくなったので消して

#define f(i,e)for(i=e+1;i--;)
#define m(p,q)(p<(q)?p=q:p)
q[22][22][22][22][102],*t,a,b,c,d,x;
char s[110],*p=s;
main(S){
	*****q=1;
	for(gets(s);*p;p++)f(a,20)f(b,a)f(c,b)f(d,c)
		*(t=&q[a][b][c][d][p-s])?
			x=*p-63,
			*p-75&&x||m(t[1086097],*t),
			*p-85&&x||m(t[49369],*t),
			*p-82&&x||m(t[2245],*t),
			*p-79&&x||m(t[103],*t),
			*p-73&&x||m(S,m(t[1],d<*t?d:*t+1)),
			m(t[1],*t)
		:0;
	x=!printf("%d",S-1);
}

373B