题面
牛牛有一个 s s s 串, s s s 串仅由 26 26 26 个小写英文字母组成,他现在将 s s s 串进行了无限次的复制扩展成了一个无线循环串。
例如一开始
s
s
s 为 abc
,那么牛牛就会将其变为 abcabcabc...
。
若某个字符串保留其原本字符出现的顺序,并且按照顺序取出若干个字符。
可以不连续,可以不取。
我们称取出的这若干个字符连成的字符串为一个子序列。
若连续取出某个字符串的前 k k k 个字符,组成一个子串,我们称该字符串为原串长度为 k k k 的前缀。
对于一个字符串 t t t,若某字符串的至少一个子序列为 t t t。则称它是一个含 t t t 序列串。
牛牛想要知道对于给定的 t t t,他想要知道 s s s 的一个最短前缀满足它是一个含 t t t 序列串,它的长度有多长?
由于答案可能非常大,所以他要求你输出答案对 998244353 998244353 998244353 取余数后的结果即可。
特别的,如果 s s s 串不存在任何一个前缀满足他是一个含 t t t 序列串,请输出 − 1 -1 −1 表示无解。
t
t
t 串中除了
26
26
26 个英文字母以外还会出现 *
,表示一个通配符。
统配符可以视为任意字母。
例如循环
s
s
s 串为 abcabcabcabc...
,
t
t
t 串为 a∗ca
时,最短含
t
t
t 序列前缀长
4
4
4。
而当
t
t
t 串为 a∗∗ca
时,最短含
t
t
t 序列前缀长
7
7
7。
除此之外,牛牛输入的 t t t 串还可能非常非常长,最长可以达到 1 0 1 0 5 10^{10^5} 10105 这么长。
所以他想了一种压缩方法,来快速读入 t t t 串。
具体来说,它输入的
t
t
t 串中除了 *
和
26
26
26 个小写英文字母以外,还会跟有一些正整数。
在读入字符串时,这些数字表示它前面字母或者 *
重复的次数。
例如 a5bc*3
,表示 aaaaabc***
。输入的正整数不含前导
0
0
0。
数据范围
对于前
10
%
10 \%
10% 的测试数据保证
1
≤
n
≤
100
,
1
≤
∣
s
∣
,
∣
t
∣
≤
10
1 \leq n \leq 100,1 \leq \lvert s \rvert, \lvert t \rvert \leq 10
1≤n≤100,1≤∣s∣,∣t∣≤10且
t
t
t 串中不包含数字以及 *
。
对于前 20 % 20 \% 20% 的测试数据保证 1 ≤ n ≤ 100 , 1 ≤ ∣ s ∣ , ∣ t ∣ ≤ 10 1 \leq n \leq 100,1 \leq \lvert s \rvert, \lvert t \rvert \leq 10 1≤n≤100,1≤∣s∣,∣t∣≤10且 t t t 串中不包含数字。
对于前 30 % 30 \% 30% 的测试数据保证 1 ≤ n ≤ 1000 , 1 ≤ ∣ s ∣ , ∣ t ∣ ≤ 1000 1 \leq n \leq 1000,1 \leq \lvert s \rvert, \lvert t \rvert \leq 1000 1≤n≤1000,1≤∣s∣,∣t∣≤1000 且 t t t 串中不包含数字。
对于前 60 % 60 \% 60% 的测试数据保证 1 ≤ n ≤ 1 0 5 , 1 ≤ ∣ s ∣ ≤ 1 0 4 , 1 ≤ ∣ t ∣ ≤ 1 0 5 1 \leq n \leq 10^5, 1 \leq \lvert s \rvert \leq 10^4, 1 \leq \lvert t \rvert \leq 10^5 1≤n≤105,1≤∣s∣≤104,1≤∣t∣≤105 且 t t t 串中的数字值域范围在 [ 1 , 1 0 9 ] [1, 10^9] [1,109] 内。
对于前 100 % 100 \% 100% 的测试数据保证 1 ≤ n ≤ 1 0 5 , 1 ≤ ∣ s ∣ ≤ 1 0 4 , 1 ≤ ∣ t ∣ ≤ 1 0 5 , ∑ ∣ t ∣ ≤ 1 0 6 1 \leq n \leq 10^5,1 \leq \lvert s \rvert \leq 10^4,1 \leq \lvert t \rvert \leq 10^5, \sum \lvert t \rvert \leq 10^6 1≤n≤105,1≤∣s∣≤104,1≤∣t∣≤105,∑∣t∣≤106 且 t t t 串中的数字值域范围在 1 0 1 0 5 10^{10^5} 10105 内。
注意, ∣ t ∣ \lvert t\rvert ∣t∣ 仅表示输入时的压缩串的长度,不代表解压缩后的长度,解压后 t t t 串的长度最长可以达到 1 0 1 0 5 10^{10^5} 10105。
题解
这是一道暴力模拟(ex)题:
对于
t
t
t 串中的每一种字符,我们都必须先把
s
s
s 串中的该字符匹配完才能匹配下一个字符,所以我们就求出该字符在
s
s
s 串中的数量,以及位置,然后把该字符需要匹配的数量分为能匹配完整个
s
s
s 环的部分,和不能匹配完的部分。这个数量边读入边取模即可。
然后就是亿堆ex的细节
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e6+10;
const ll P=998244353;
ll n,m,len,k,pos[35][N],cnt[35];
ll ans,s1,s2;
char c[N],t[N];
void prework(){
for(int i=1;i<=len;++i)pos[c[i]-'a'+1][++cnt[c[i]-'a'+1]]=i;
}
void solve(int ck,int s){
k=pos[ck][s];
ans=(ans+k)%P;
}
int erfen(int ck,int k){
int l=1,r=cnt[ck]+1;
while(l<r){
int mid=(l+r)>>1;
if(pos[ck][mid]>k)r=mid;
else l=mid+1;
}
return l;
}
void work(){
int len_t=strlen(t),ck;k=0;
//cout<<"=----"<<len<<endl;
ll s=0;
char ck311='0';
for(int i=1;i<=len_t;++i){
//cout<<"FFF "<<i<<" "<<ck<<endl;
if(t[i]>='a'&&t[i]<='z'){
if((!cnt[t[i]-'a'+1])){
ans=-1;return;}}
if(t[i]>='0'&&t[i]<='9'){
s2=s2*10+t[i]-'0';
s1=(s1*10+s2/cnt[ck])%P;
s2%=cnt[ck];
}
else{
if(i>1){
if(t[i-1]<'0'||t[i-1]>'9')s2=1;
//cout<<i<<" "<<s1<<" "<<s2<<endl;
int l=erfen(ck,k);
if(l<=cnt[ck])ans+=pos[ck][l]-k,k=pos[ck][l];
else ans+=len-k,k=0,ans+=pos[ck][erfen(ck,k)],k=pos[ck][erfen(ck,k)];
if(s2)s2--;
else if(s1)s1--,s2=cnt[ck]-1;
if(s1){
if(s2)ans=(ans+s1*len%P)%P;
else ans=(ans+(s1-1)*len%P)%P,s2=cnt[ck];
}
//cout<<"FAQ "<<ans<<endl;
if(s2){
l=erfen(ck,k);
if(l+s2-1>cnt[ck]){
ans=(ans+P+P+len-k)%P;
s2-=cnt[ck]-l+1;
k=0;
solve(ck,s2);
}
else{
ans=(ans+P+pos[ck][l+s2-1]-k)%P;
k=pos[ck][l+s2-1];
}
}
}
s1=0;s2=0;
ck311=t[i];
if(ck311=='*')ck=28;
else ck=t[i]-'a'+1;
}
}
}
int main(){
// freopen("ex.in","r",stdin);
// freopen("ex.out","w",stdout);
scanf("%s",c);
len=strlen(c);
cnt[28]=len;
for(int i=len;i>0;--i)c[i]=c[i-1];
for(int i=1;i<=len;++i)pos[28][i]=i;
//cout<<"FFFFAQQQ "<<len<<endl;
prework();
scanf("%d",&n);
for(int i=1;i<=n;++i){
t[0]='0';ans=0;k=0;
scanf("%s",t+1);
work();
printf("%lld\n",ans);
}
return 0;
}