简要题意:
给你一个残缺的串 S S S,里面有一些空位,你需要填充里面的空位使得 T T T是 S S S的字串。
多次询问字典序第 k k k小的填充方案,输出哈希值。
题解:
倍增裸题。
反正我这辈子都在考场上写不出字典序倍增
考虑建立KMP自动机,状态 [ i ] [ j ] [i][j] [i][j]表示已经决定了前 i − 1 i-1 i−1个字符的填充,当前匹配到了第 j j j个字符。
选择siz最大的节点作为后继节点。
预处理倍增后在KMP自动机的位置,倍增需要跳的rk,倍增过程中的哈希值。
然后大力倍增就行了。
估计没有谁跟我一样考场上写了结构体没调出来。。。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
inline char pk(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1;}
int get_s(char *s){
int len=0;char c;while(isspace(c=gc()));
while(s[len++]=c,!isspace(c=gc())&&c!=EOF);
return s[len]='\0',len;
}
char gs(){while(isspace(pk()))++p1;return *p1++;}
template<typename T>T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
inline ll gl(){return get<ll>();}
}
using namespace IO;
using std::cerr;
using std::cout;
template<typename T>void ckmin(T &a,T b){a>b?a=b:0;}
cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
cs int N=5e4+7;
cs ll INF=1e18+1e7;
int pw[N],n,q,m;
char s[N],t[N];
int nxt[22];//KMP
int to[22][22];//KMP自动机
int suf[N];//后缀哈希值
int c0[N];
std::vector<int> vec[N],zero;
struct state{
ll rk[17];int h[17],ps[17],lim;
//倍增跳过的排名,倍增过程里面的哈希值,倍增后在KMP自动机上面的位置
ll siz;//有多少种合法的后继决策能够到达KMP终止状态,与INF取min
ll pre[13];//走每个孩子要减掉的排名有多少
int son;
}st[N][22];
bool vis[N][22];
//到了第i个位置,第i个位置还没有决策,当前在KMP自动机的第j的位置上面的状态转移
//找到第一个能够接纳它的KMP终止位置,然后按照排名在后面空位填数
//倍增过程除了最后一步,其余都不经过KMP终止位置。
void dfs(int i,int j){//当前位置,在KMP上的位置
if(vis[i][j])return ;vis[i][j]=true;
if(i>n)return ;
if(j==m){
st[i][j].siz=pow(10,std::min(18,c0[i]));
for(int re k=0;k<17;++k)st[i][j].rk[k]=INF;
return ;
}
int son=0;ll siz=0;
for(int re c=0;c<vec[i].size();++c){
int t=to[j][vec[i][c]];dfs(i+1,t);
ll pre=st[i][j].siz,now;st[i][j].pre[c]=pre;
ckmin(st[i][j].siz+=st[i+1][t].siz,INF);
now=st[i][j].siz-pre;
if(now>siz)son=c,siz=now;
}st[i][j].son=vec[i][son];
if(st[i][j].siz==0)return ;
st[i][j].rk[0]=st[i][j].pre[son];
st[i][j].h[0]=mul(vec[i][son],pw[n-i]);
st[i][j].ps[0]=to[j][vec[i][son]];
for(int re p=1;p<=16;++p){
int t=st[i][j].ps[p-1],k=i+(1<<(p-1));
if(k>n+1)break;
st[i][j].rk[p]=std::min(st[i][j].rk[p-1]+st[k][t].rk[p-1],INF);
st[i][j].h[p]=add(st[i][j].h[p-1],st[k][t].h[p-1]);
st[i][j].ps[p]=st[k][t].ps[p-1];
}
}
void work(int i,int j,ll rk,int hs){
if(rk>st[i][j].siz){cout<<"-1\n";return ;}
for(int re p=16;~p&&j!=m;--p){
int t=st[i][j].ps[p],k=i+(1<<p);if(k>n+1)continue;
if(st[i][j].rk[p]<rk&&st[i][j].rk[p]+st[k][t].siz>=rk){
rk-=st[i][j].rk[p],Inc(hs,st[i][j].h[p]),i=k,j=t;
}
}
if(j==m){
Inc(hs,suf[i]);--rk;
for(int re c=zero.size()-1;~c&&zero[c]>=i&&rk;--c){
Inc(hs,mul(rk%10,pw[n-zero[c]]));
rk/=10;
}
cout<<hs<<"\n";return ;
}
for(int re c=0;c<vec[i].size();++c){
int t=to[j][vec[i][c]];
if(st[i][j].pre[c]<rk&&st[i+1][t].siz+st[i][j].pre[c]>=rk){
return work(i+1,t,rk-st[i][j].pre[c],add(hs,mul(vec[i][c],pw[n-i])));
}
}
}
void solve(){
n=gi(),q=gi();zero.clear();
m=get_s(t+1);get_s(s+1);
for(int re i=1;i<=n;++i){
vec[i].clear();
if(s[i]!='?'){
if(i==1&&s[i]=='0'){
while(q--)gl(),cout<<"-1\n";
return ;
}
vec[i].push_back(s[i]^48);
c0[i]=0;
}else {
for(int re j=(i==1);j<=9;++j)vec[i].push_back(j);
zero.push_back(i);c0[i]=1;
}
}suf[n+1]=0;
for(int re i=n;i;--i){
int val=vec[i].size()==1?vec[i].back():0;
suf[i]=add(suf[i+1],mul(val,pw[n-i]));
c0[i]+=c0[i+1];
}
for(int re i=2,j=0;i<=m;++i){
while(j&&t[j+1]!=t[i])j=nxt[j];
if(t[j+1]==t[i])++j;nxt[i]=j;
}memset(to,0,sizeof to);
to[0][t[1]^48]=1;
for(int re i=1,k;i<=m;++i){k=i;
while(k){
if(!to[i][t[k+1]^48])
to[i][t[k+1]^48]=k+1;
k=nxt[k];
}
if(!to[i][t[k+1]^48])
to[i][t[k+1]^48]=k+1;
}
for(int re i=1;i<=n+1;++i)memset(st[i],0,sizeof st[i]);
st[n+1][m].siz=1;memset(vis,0,sizeof vis);
dfs(1,0);while(q--)work(1,0,gl(),0);
}
signed main(){
#ifdef zxyoi
freopen("shuawang.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
freopen("shuawang.in","r",stdin);freopen("shuawang.out","w",stdout);
#endif
#endif
pw[0]=1;for(int re i=1;i<N;++i)pw[i]=mul(pw[i-1],10);
int T=gi();while(T--)solve();
return 0;
}