题目传送门

题意简述:给出 \(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;
}

CF1466G Song of the Sirens的更多相关文章

  1. Codeforces 1466G - Song of the Sirens(哈希)

    Codeforces 题面传送门 & 洛谷题面传送门 事实证明,有的难度评分不算很高.涉及的知识点不算很难的题目也能出得非常神仙 首先考虑如何暴力求答案.注意到一个文本串 \(T\) 在 \( ...

  2. 读懂UI设计的心理学

    好文转载,版权归原作者 作为UI设计师,对待用户就像对待婴儿,知道如何通过界面设计诱导用户非常重要,这就需要了解心理学方面的知识了.今天分享一篇日本设计师的好文,结合心理学与设计,教你读懂心理学,提高 ...

  3. UVA 590 二十一 Always on the run

     Always on the run Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit ...

  4. python瓦登尔湖词频统计

    #瓦登尔湖词频统计: import string path = 'D:/python3/Walden.txt' with open(path,'r',encoding= 'utf-8') as tex ...

  5. TWELP™ Vocoder

    TWELP™ Vocoder   DSP Innovations Inc. (DSPINI) announces new class of proprietary vocoders for wide ...

  6. How to Pronounce the Idiom: ‘Out Like a Light’

    How to Pronounce the Idiom: ‘Out Like a Light’ Share Tweet Share Tagged With: Idioms English is full ...

  7. 哥谭第四季/全集Gotham迅雷下载

    <哥谭>(Gotham)第三季刚刚结束,第四季首集的集名就公布了.<Pax Penguina>这个集名在拉丁语中意味着「Pax Romana」,也就是「罗马式的和平」(Roma ...

  8. Chapter 3 Phenomenon——9

    "You were over there," I suddenly remembered, and his chuckle stopped short. “你之前不在这里”我突然记 ...

  9. [label][转载][web-design-psychology]网页设计心理

    原文出处: http://mux.alimama.com/posts/1301 Tip1:信息不要同时全部展示,阶段性地向用户展示当前场景里必要的信息 设计师经常犯的错误:同时将大量信息展示给用户.不 ...

随机推荐

  1. 关于takin-data,你想知道的都在这里(二)trace日志篇

    相信大家在使用takin的过程中都见到过压测过程中实时展示的请求流量明细和请求详情了吧,像这样: 还有这样: 这样的请求流量明细和调用链详情是怎么实现的呢,今天就带大家探究下. 在前面的启动命令篇(h ...

  2. nsq - 一条消息的生命周期(一)

    经过前面几篇的学习,相信大家对nsq已经有了一个大概的了解,我在写这篇文章的时候也看了很多其他人写的教程,发现大家对于分析系统每个点写的很不错,但是都很少有整体串起来一起走一遍,所以,我打算分成2-3 ...

  3. JVM:GC Roots

    JVM:GC Roots 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 JVM 垃圾回收的时候如何确定垃圾 什么是垃圾 简单来说就是内存中已经不再被使用的空间就 ...

  4. CSP-S 2021 爆零记

    前言 本人今年高二蒟蒻OIer,高一刚刚接触OI. 感觉可能要直接退役了555~ 希望还有机会靠NOIP翻盘 Day - 暑假 为了备战CSP提前返校,与xzh一起划水,总之刷了不少题,我也大受震撼 ...

  5. gcc中预定义的宏__GNUC__

    转载:gcc中预定义的宏__GNUC__ - Cccarl - 博客园 (cnblogs.com) 今天在看Linux系统编程这本书的代码的时候看到了__GNUC__,不太清楚这个宏所以去查了一下,以 ...

  6. 【数据结构&算法】04-线性表

    目录 前言 线性表的定义 线性表的数据类型&操作 线性表操作 数据类型定义 复杂操作 线性表的顺序存储结构 顺序存储结构的定义 顺序存储方式 数据长度和线性表长度的区别 地址的计算方法 顺序存 ...

  7. 关于docker中容器可以Ping通外网,真机无法Ping通容器的问题

    首先我们要知道整体的框架结构,docker是我们安装在centos7上的,而centos7是安装在vmware上.其中docker中还有若干容器运行. 整体框架图如下: 我们将它分为两部分,一部分是d ...

  8. leetcode 剪绳子系列

    ### 剪绳子一 利用动态规划 状态转移方程 为啥是这个样子?首先  代表 长度为i的绳子被剪去j,且继续剪(子问题)  表示长度为i的绳子被剪去j,不剪了的乘积 注意初始化: n<2 f=0 ...

  9. RDD的详解、创建及其操作

    RDD的详解 RDD:弹性分布式数据集,是Spark中最基本的数据抽象,用来表示分布式集合,支持分布式操作! RDD的创建 RDD中的数据可以来源于2个地方:本地集合或外部数据源 RDD操作 分类 转 ...

  10. FZU_DS_2019_SequenceList

    单选题 2-1   数组A[1..5,1..6]每个元素占5个单元,将其按行优先次序存储在起始地址为1000的连续的内存单元中,则元素A[5,5]的地址为:  A.1120      B.1125   ...