题目传送门

题意简述:给出 \(n,s_0,t\ (n=|t|)\),定义 \(s_i=s_{i-1}+t_i+s_{i-1}\)。多次询问给出 \(k,m\),求 \(m\) 在 \(s_k\) 中的出现次数。记 \(L=\sum |m|\),则 \(L\leq 10^6\)。

Goodbye 2020 的 G。我当时怎么没做出来呢?


key observation:若 \(|m|\leq|s_i|\),那么答案可以分成两部分计算:

  • 一部分是 \(m\) 完整地出现在 \(s_k\) 中的次数。那么根据 \(s\) 的定义,设 \(m\) 在 \(s_i\) 中出现了 \(f(m,s_i)\) 次,则 \(m\) 在 \(s_k\) 中出现了 \(2^{k-i}f(m,s_i)\) 次。这一点是显然的。
  • 另一部分是 \(m\) 中有一个字符被 \(t_{i+1},t_{i+2},\cdots,t_k\) 的某个字符匹配,剩下来的前缀出现在 \(s_i\) 的后缀,后缀出现在 \(s_i\) 的前缀的次数之和。考虑 \(t\) 的某个位置 \(p\ (i<p\leq k)\) 上的字符 \(t_p\) 在 \(s_k\) 中被复制的次数(只考虑该位置 \(p\),而不考虑与 \(t_p\) 相同的其它位置上的字符),根据 \(s\) 的定义,它被复制了 \(2^{k-p}\) 次。枚举 \(m\) 中被匹配的位置 \(j\) 和 \(t[i+1:k]\) 中与 \(m_j\) 匹配的位置 \(p\),则贡献可以写成 \(\sum_{j=1}^{|m|}\sum_{p=i+1}^k2^{k-p}[m[1:j-1]=s_i[|s_i|-j+1:|s_i|]\land m_j=t_p\land m[j+1:r]=s_i[1:r-j]]\)。将其改写为 \(\sum_{j=1}^{|m|}[m[1:j-1]=s_i[|s_i|-j+1:|s_i|]\land m[j+1:r]=s_i[1:r-j]]\sum_{p=i+1}^k2^{k-p}[m_j=t_p]\)。注意到后面这坨东西在 \(i,k\) 确定的情况下,对于相同的 \(m_j\) 给出的答案是相同的。因为 \(m_j\) 的取值只有 \(26\) 种,那么预处理出来即可。
  • 怎么预处理?注意到相同的 \(t_p\) 对于不同的 \(i,k\) 贡献可能不同,很讨厌。将其写为 \(\dfrac{\sum_{p=i+1}^n2^{n-p}[m_j=t_p]-\sum_{p=k+1}^n2^{n-p}[m_j=t_p]}{2^{n-k}}\),那么对于每个字符 \(c\),预处理出 \(g(c,i)=\sum_{p=i+1}^n2^{n-p}[t_p=c]\) 与 \(2\) 的幂的逆元,就可以 \(\mathcal{O}(1)\) 计算上式(\(\dfrac{g(m_j,i+1)-g(m_j,k+1)}{2^{n-k}}\))。即对于每个字符 \(c\) 和字符串编号 \(i\),预处理出在 \(t[i+1:n]\) 中所有与 \(c\) 相等的 \(t_p\) 在 \(s_n\) 中被复制的次数,就可以快速计算在 \(t[i+1:k]\) 中所有与 \(c\) 相等的 \(t_p\) 在 \(s_k\) 中被复制的次数。

思路 1:找到一个最小的 \(pos\) 使得 \(|s_{pos}|\geq \max(|m|)\)(如果不存在则为 \(n\))。对于每一个 \(j\in[0,pos]\),建出 \(s_j\) 的后缀数组,然后处理所有 \(k=j\) 的询问(若 \(j=pos\) 则处理所有 \(k\geq j\) 的询问)即可(SA 的主要作用是求出 \(m\) 在 \(s_i\) 中的出现次数)。判断 \(m,s\) 的前缀后缀是否相等需要用哈希。时间复杂度 \(\mathcal{O}(L\log L)\)。常数较大(而且我还写挂了)。

思路 2:在上面的思路中,对于一个询问,我们主要关注的是它的 \(k\)。这样在求出现次数的时候必须使用后缀数据结构(因为如果有很多 \(k\) 都很大而 \(|m|\) 很小的询问,同时有一个 \(|m|\) 很大的询问,那么直接哈希判断的复杂度可以达到 \(qL\)),比较麻烦。但是注意到对于那些 \(|m|\) 很小的询问,我们没有必要让它与 \(s_{pos}\) 匹配,直接找到一个最小的 \(i\) 满足 \(|s_i|\geq |m|\),让它与 \(s_i\) 匹配就好了。如果 \(i>k\) 则显然没有出现(因为 \(|s_k|<|m|\))。这样求出现次数就可以直接哈希或者 KMP 了,查询的时间复杂度可以降为 \(\mathcal{O}(L)\)。总时间复杂度即为 \(\mathcal{O}(n|\Sigma|+L)\)。

/*
Powered by C++11.
Author : Alex_Wei.
*/ #pragma GCC optimize(3) #include <bits/stdc++.h>
using namespace std; using ll = long long;
using ull = unsigned long long;
using pii = pair <int,int>; #define fi first
#define se second
#define mpi make_pair
#define pb emplace_back
#define mcpy(x,y) memcpy(x,y,sizeof(y)) const int L=2e6+5;
const int N=1e5+5;
const int mod=1e9+7; void add(ll &x,int y){
x+=y; if(x>=mod)x-=mod;
} ull hs1[L],hs2[L],p[L];
ull q1(int l,int r){
return hs1[r]-hs1[l-1]*p[r-l+1];
} ull q2(int l,int r){
return hs2[r]-hs2[l-1]*p[r-l+1];
} int n,q,len,mxlen;
ll f[N][26],pw[N],iv[N],ans[N];
char s[L],t[N];
string qs[N];
vector <pii> qu[L]; int main(){
scanf("%d%d%s%s",&n,&q,s+1,t+1),pw[0]=p[0]=iv[0]=1;
for(int i=1;i<=n;i++)pw[i]=pw[i-1]*2%mod,iv[i]=iv[i-1]*(mod+1>>1)%mod;
for(int i=1;i<L;i++)p[i]=p[i-1]*131;
for(int i=n;i;i--){
for(int j=0;j<26;j++)f[i][j]=f[i+1][j];
add(f[i][t[i]-'a'],pw[n-i]);
} for(int i=1;i<=q;i++){
int id; cin>>id>>qs[i],mxlen=max(mxlen,(int)qs[i].size());
qu[qs[i].size()].pb(mpi(i,id));
} int pre=0,pos=0; len=strlen(s+1);
while(1){
for(int i=1;i<=len;i++)hs1[i]=hs1[i-1]*131+s[i];
for(int l=pre+1;l<=len;l++)for(pii it:qu[l]){
string t=qs[it.fi]; int id=it.fi,k=it.se,slen=t.size();
if(k<pos)continue;
for(int i=1;i<=slen;i++)hs2[i]=hs2[i-1]*131+t[i-1];
ull ap=0,hs=hs2[slen];
for(int i=slen;i<=len;i++)ap+=q1(i-slen+1,i)==hs;
ans[id]=ap*pw[k-pos]%mod;
for(int i=1;i<=slen;i++){
int l=i-1,r=slen-i,it=t[i-1]-'a';
if(q1(len-l+1,len)==q2(1,l)&&q1(1,r)==q2(slen-r+1,slen))
add(ans[id],(f[pos+1][it]-f[k+1][it]+mod)*iv[n-k]%mod);
}
} if(len>=mxlen)break;
for(int i=1;i<=len;i++)s[len+i+1]=s[i];
s[len+1]=t[++pos],pre=len,len=(len<<1)+1;
} for(int i=1;i<=q;i++)cout<<ans[i]<<"\n";
return 0;
}

最新文章

  1. java读写中文文件
  2. String定义与方法
  3. Nosql释义
  4. Jquery 回到顶部
  5. UNICODE,GBK,UTF-8区别
  6. VC++中操作XMLWin32实例
  7. C++实现线程池 .
  8. php 将pdf转成图片且将图片拼接
  9. Linux查看用于终止进程命令
  10. C语言数据结构基础学习笔记——树
  11. Java 8 时间日期
  12. HDU5616 天平能否称出物体重量问题 01背包变形或者折半搜索
  13. Linux下载命令之rpm和yum比较
  14. 【转】Principles of training multi-layer neural network using backpropagation
  15. nmon
  16. 《快学Scala》第一章 基础
  17. thinkphp多级分类
  18. Lodash js数据操作库
  19. 无网络环境用pip安装python类包
  20. 使用class-dump

热门文章

  1. 【UE4 C++ 基础知识】&lt;10&gt;资源的引用
  2. 短短 29 天,应对高峰 100W+ 访问,看浙大如何交出满分答卷
  3. 封装一个的toast弹出框(vue项目)
  4. 微信小程序添加外部地图服务数据
  5. Asp.net Core使用EFCore+Linq进行操作
  6. java中的软,弱,虚引用介绍与特性分析
  7. 2021.8.12考试总结[NOIP模拟37]
  8. poj 2060 Taxi Cab Scheme(DAG图的最小路径覆盖)
  9. Docker的centos镜像内无法使用systemctl命令的解决办法
  10. centos 下安装docker