所有的匹配子串必然是由表达式中的正常字符串连接起来的,而连接的符号串很容易表达:当只存在
?
时,两个子串的距离等于
那么考虑按表达式中的正常字符串来进行dp,简单推出一个方程:
然而上述方程是错误的,因为当同一个串连接了之前的合法串时,会导致第一个位置相同的串被重复计数。考虑直接用bitset记录每个串的第一个位置,那么当连接串包含
∗
时,方程变为
显然状态数最多的时候不会超过
n2
个,单层状态数不会超过
n
个,转移的复杂度是
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<vector>
#include<queue>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
typedef bitset<3000> bt;
int nx[3010][26],gfa[3010],tn,n,m,sn,xd[3010],sle[3010],ct=0;bool fd[3010];
char cz[3010],xz[3010];
bt dp[2][3010];
vector<int>vc[3010],acd[3010];
void _psh(int l,int r,int si){
int t,d;for(sle[si]=r-l+1,d=0;l<=r;++l){
t=xz[l]-'a';
if(nx[d][t])d=nx[d][t];
else{
nx[d][t]=++tn;d=tn,clr(nx[tn]);
}
}
acd[d].push_back(si);
};
void _clgfa(){
int i,t,d;queue<int>qe;
for(i=0;i<26;++i)if(nx[0][i])
gfa[nx[0][i]]=0,qe.push(nx[0][i]);
for(;!qe.empty();){
t=qe.front();qe.pop();
for(i=0;i<26;++i)if(nx[t][i]){
for(d=gfa[t];d&&!nx[d][i];d=gfa[d]);
gfa[nx[t][i]]=nx[d][i],qe.push(nx[t][i]);
}
}
};
void __cl(){
int i,j,d,t,x;for(i=d=0;i<n;++i){
t=cz[i]-'a';
if(nx[d][t])d=nx[d][t];
else{
for(x=gfa[d];x&&!nx[x][t];x=gfa[x]);
d=nx[x][t];
}
for(x=d;x;x=gfa[x])for(j=0;j<acd[x].size();++j)
vc[acd[x][j]].push_back(i);
}
};
int cu,qi;
int _bf_eq(int si,int x){
int b=0,e=vc[si].size()-1,m;
while(b<=e){
m=(b+e)>>1;
if(vc[si][m]==x)return m;
else if(vc[si][m]>x)e=m-1;
else
b=m+1;
}
return -1;
};
int _bf_le(int si,int x){
int b=0,e=vc[si].size()-1,m,t=-1;
while(b<=e){
m=(b+e)>>1;
if(vc[si][m]<=x)t=m,b=m+1;
else
e=m-1;
}
return t;
};
void _cl(int si){
int i,j,t;
if(!si){
cu=0,qi=1;
if(fd[si]){
for(clr(dp),i=0;i<vc[si].size();++i){
if(vc[si][i]-sle[si]-xd[si]+1>=0)
dp[cu][i][vc[si][i]-sle[si]-xd[si]+1]=1;
}
}
else{
for(clr(dp),i=0;i<vc[si].size();++i){
for(j=0;vc[si][i]-sle[si]-xd[si]+1>=j;++j)
dp[cu][i][j]=1;
}
}
}
else{
swap(cu,qi);
if(fd[si]){
for(i=0;i<vc[si].size();++i){
t=_bf_eq(si-1,vc[si][i]-sle[si]-xd[si]);
dp[cu][i]=t>=0?dp[qi][t]:0;
}
}
else{
for(i=1;i<vc[si-1].size();++i)dp[qi][i]|=dp[qi][i-1];
for(i=0;i<vc[si].size();++i){
t=_bf_le(si-1,vc[si][i]-sle[si]-xd[si]);
dp[cu][i]=t>=0?dp[qi][t]:0;
}
}
}
};
void cl(){
int i,j,k,d;scanf("%s",cz);scanf("%s",xz);
n=strlen(cz),m=strlen(xz);
for(i=0;i<=3000;++i)acd[i].clear(),vc[i].clear();
for(i=tn=sn=0,clr(nx[0]);i<m;){
xd[sn]=0,fd[sn]=1;for(;i<m&&xz[i]<'a';++i){
if(xz[i]=='*')fd[sn]=0;
if(xz[i]=='?')xd[sn]++;
}
if(i==m)break;
for(j=i;i<m&&xz[i]>='a';++i);_psh(j,i-1,sn++);
}
if(!sn){
if(fd[0])printf("Case %d: %d\n",++ct,max(0,n-xd[0]+1));
else{
for(j=0,k=xd[0]?xd[0]:1;k<=n;++k)j+=(n-k+1);
printf("Case %d: %d\n",++ct,j);
}
return;
}
_clgfa();__cl();
for(i=0;i<sn;++i)if(vc[i].empty()){
printf("Case %d: 0\n",++ct);return;
}
for(i=0;i<sn;_cl(i++));
for(xd[sn]=0,fd[sn]=1,i=m-1;i>=0&&xz[i]<'a';--i){
if(xz[i]=='*')fd[sn]=0;
if(xz[i]=='?')xd[sn]++;
}
if(fd[sn]){
for(k=i=0;i<vc[sn-1].size()&&vc[sn-1][i]<=n-1-xd[sn];++i)k+=dp[cu][i].count();
printf("Case %d: %d\n",++ct,k);
}
else{
for(i=1;i<vc[sn-1].size();++i)dp[cu][i]|=dp[cu][i-1];
for(k=i=0;i<n;++i){
d=_bf_le(sn-1,i-xd[sn]);
k+=(d>=0?dp[cu][d].count():0);
}
printf("Case %d: %d\n",++ct,k);
}
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int t;scanf("%d",&t);while(t--)cl();
return 0;
};