题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=4043
题解
首先补全字符串。
设表示字符串的前位,为代表三个串字典序都相等,代表前两个串字典序相等而第二个<第三个,代表第一个<第二个=第三个,代表第一个<第二个<第三个,这样如果直接转移显然非常麻烦。
考虑设表示三个串现在的字符分别为,状态从转移到的方案数,这样枚举代表的字符顺序,转移非常显然,用这个来转移也很显然了。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int maxn=1000000;
const int mod=1000000009;
int n,g[30][30][30][4][4],f[maxn+10][4],ch[3][maxn+10];
char s[3][maxn+10];
int main()
{
for(int i=0; i<=27; ++i)
{
for(int j=0; j<=27; ++j)
{
for(int k=0; k<=27; ++k)
{
int li,ri,lj,rj,lk,rk;
if(i==27)
{
li=1;
ri=26;
}
else
{
li=ri=i;
}
if(j==27)
{
lj=1;
rj=26;
}
else
{
lj=rj=j;
}
if(k==27)
{
lk=1;
rk=26;
}
else
{
lk=rk=k;
}
for(int a=li; a<=ri; ++a)
{
for(int b=lj; b<=rj; ++b)
{
for(int c=lk; c<=rk; ++c)
{
if((a<b)&&(b<c))
{
++g[i][j][k][0][3];
}
else if((a<b)&&(b==c))
{
++g[i][j][k][0][2];
}
else if((a==b)&&(b<c))
{
++g[i][j][k][0][1];
}
else if((a==b)&&(b==c))
{
++g[i][j][k][0][0];
}
if(a==b)
{
++g[i][j][k][1][1];
}
else if(a<b)
{
++g[i][j][k][1][3];
}
if(b==c)
{
++g[i][j][k][2][2];
}
else if(b<c)
{
++g[i][j][k][2][3];
}
++g[i][j][k][3][3];
}
}
}
}
}
}
int t=read();
while(t--)
{
scanf("%s%s%s",s[0]+1,s[1]+1,s[2]+1);
n=0;
for(int i=0; i<3; ++i)
{
n=std::max(n,(int)strlen(s[i]+1));
}
for(int i=0; i<3; ++i)
{
int ni=strlen(s[i]+1);
for(int j=1; j<=ni; ++j)
{
if(s[i][j]=='?')
{
ch[i][j]=27;
}
else
{
ch[i][j]=s[i][j]-'a'+1;
}
}
for(int j=ni+1; j<=n; ++j)
{
ch[i][j]=0;
}
}
f[0][0]=1;
for(int i=1; i<=n; ++i)
{
for(int j=0; j<4; ++j)
{
for(int k=0; k<4; ++k)
{
f[i][j]=(f[i][j]+1ll*f[i-1][k]*g[ch[0][i]][ch[1][i]][ch[2][i]][k][j])%mod;
}
}
}
printf("%d\n",f[n][3]);
for(int i=1; i<=n; ++i)
{
for(int j=0; j<4; ++j)
{
f[i][j]=0;
}
}
}
return 0;
}