任务统计
工作日五题。(2/5)
链接
https://codeforces.com/problemset/problem/1163/D
题解
这题稍稍想一下就可以出来了
我的思路是这样的,我先想到的是枚举
∗
*
∗上填啥,从左往右依次填,这样前
i
i
i个都填上了
总的情况很多,可以考虑记录一些信息进行转移
接下来我觉得应该要记录什么信息,那我就想到了记录按照
k
m
p
kmp
kmp进行匹配的时候前缀
i
i
i在两个字符串中分别匹配到的位置
然后就出来了:
f
i
j
k
f_{ijk}
fijk表示考虑了前
i
i
i个字符,
s
s
s串匹配到
j
j
j,
t
t
t串匹配到
k
k
k,这样的最优解
这样的正确性很显然,
k
m
p
kmp
kmp的匹配是局部最优的,而且状态中考虑到了匹配位置的所有情况,那也就是说所有情况都包含在里面了,这个差的决策肯定也是局部最优整体最优的。
代码
#include <bits/stdc++.h>
#define maxn 1010
#define cl(x) memset(x,0,sizeof(x))
#define iinf 0x3f3f3f3f
using namespace std;
int l1, l2, f[1010][60][60], n;
char c[maxn];
struct kmp
{
int next[maxn], len;
char s[maxn];
void init()
{
int i, j;
scanf("%s",s+1);
len=strlen(s+1);
next[0]=next[1]=0;
for(i=2,j=0;i<=len;i++)
{
for(j=next[i-1];j and s[j+1]!=s[i];j=next[j]);
if(s[j+1]==s[i])next[i]=j+1;
else next[i]=0;
}
}
int move(int pos, char c)
{
for(;pos and s[pos+1]!=c;pos=next[pos]);
if(s[pos+1]==c)pos++;
return pos;
}
}s, t;
int main()
{
int i, j, k, len1, len2, n, ans(-iinf);
char alpha;
scanf("%s",c+1);
n=strlen(c+1);
s.init(), t.init();
memset(f,0x80,sizeof(f));
f[0][0][0]=0;
for(i=0;i<n;i++)for(j=0;j<=s.len;j++)for(k=0;k<=t.len;k++)
{
if(f[i][j][k]==0x80808080)continue;
if(c[i+1]!='*')
{
int &to=f[i+1][s.move(j,c[i+1])][t.move(k,c[i+1])];
to=max(to, f[i][j][k] + (s.move(j,c[i+1])==s.len) - (t.move(k,c[i+1])==t.len) );
}
else
{
for(alpha='a';alpha<='z';alpha++)
{
int &to=f[i+1][s.move(j,alpha)][t.move(k,alpha)];
to=max(to, f[i][j][k] + (s.move(j,alpha)==s.len) - (t.move(k,alpha)==t.len) );
}
}
}
for(j=0;j<=s.len;j++)for(k=0;k<=t.len;k++)ans=max(ans,f[n][j][k]);
printf("%d",ans);
}