题解 CF589C【Polycarp's Masterpiece】
题意
给你一个字符串 $s$,有 $n$ 次操作,每次操作将当前字符串 $s$ 复制,并将后 $k_i$ 个字符放到字符串最前面,接到当前字符串之后,接下来 $m$ 次查询,每次查询问最终字符串 $[l,r]$ 区间中有多少个字符 $c$。
$|s|,k_i\le100,1\le n,m\le 10^5,1\le l\le r\le 10^{18}$
思路
校内模拟赛 $\text C$ 题,赛时做出来了!
不知道为什么这场 $\text{CF}$ 好像被删了,交上去会 $\text{UKE}$。
这应该是到目前为止这道题的第三种做法,另外两种做法可以参考 @ezoiHQM 的可持久化 $\text{FHQ}$ 和 @dqstz 的可持久化线段树。
这里我提供一种比较好想、好写,但是依赖于 $k$ 的范围的做法。
我们知道,经过 $i$ 次操作,$s$ 的长度就会变为 $l\times 2^i$($l$ 为 $s$ 的初始长度),进行 $10^5$ 次操作是完全没有意义的,因为查询只到 $10^{18}$,所以进行 $60$ 次操作就完全够了($2^{60}>10^{18}$)。
首先思考如何求出位置 $p$ 的字符。考虑一次操作之后的字符串长这样:

考虑设计函数 $\text{getch}(p,d)$ 表示求第 $p$ 位置的字符,当前正处理第 $d$ 次操作。
- 若 $d=0$,则直接返回 $s_p$;
- 若 $d\ne0$,
- 若 $p$ 落在区间 $[A,B]$ 之间,则调用 $\text{getch}(p,d-1)$ 进行递归处理。
- 若 $p$ 落在区间 $B'$ 中,找到其在 $B$ 中对应的位置,递归即可。考虑 $B'$ 的结束位置为 $y=l\times2^{d-1}+k_d$,则调用函数 $\text{getch}(l\times2^{d-1}-y+p,d-1)$;
- 若 $p$ 落在区间 $A'$ 中,找到其在 $A$ 中对应的位置,递归即可。考虑 $B'$ 的结束位置为 $y=l\times2^{d-1}+k_d$,则调用函数 $\text{getch}(p-y,d-1)$。
每次递归都会将 $d$ 减 $1$,由于 $d=O(\log p)$,所以一次 $\text{getch}(p,d)$ 的调用消费为 $O(\log p)$。
考虑将每次询问差分成 $r$ 的前缀和减去 $l-1$ 的前缀和,对于一次前缀和询问,记其为 $\text{ask}(r,d,x)$ 表示询问 $[1,r]$ 区间中 $x$ 的出现次数,当前正在处理第 $d$ 次操作。还是那张图:

- 若 $d=0$,考虑预处理出原字符串中每个字符出现次数的前缀和,则可以 $O(1)$ 查询;
- 若 $d\ne0$,
- 若 $r$ 落在区间 $[A,B]$ 之间,则返回 $\text{ask}(r,d-1,x)$;
- 若 $r$ 落在区间 $B'$ 中,贡献分为 $[A,B]$、$[B'_l,r]$ 两部分,其中第一部分贡献可以通过预处理 $s$ 中每个字母的出现次数 $O(1)$ 计算,对于第二部分,由于 $k$ 很小,可以通过预处理每次的 $B$ 部分的字母出现次数的前缀和 $O(1)$ 计算,直接返回;
- 若 $r$ 落在区间 $A'$ 中,贡献分为 $[A,B]$、$B'$ 和 $[A'_l,r]$ 三部分,前两部分直接按照上一种情况处理,对于第三部分,找到其在 $A$ 中对应的位置,递归询问即可。考虑 $B'$ 的结束位置为 $y=l\times2^{d-1}+k_d$,则返回前两部分的答案和加上 $\text{ask}(r-y,d-1,x)$。
同样,由于 $d=O(\log r)$,调用一次 $\text{ask}(r,d,x)$ 的调用消费为 $O(\log r)$。
总时间复杂度为 $O(\sum k\log r(\log r+|\sum|)+m\log r)$。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=1e5+10;
char str[110];
int l,n,m;
int pr[26][110],k[N],pre[26][70][110];
/*
pre[i][j][k]=第 j 天后 k_j 个字符中前 k 个字符中有多少个 i
由于询问区间知道 10^18,则只需开 26x\log2(10^18)x100 的数组即可
对于 1 天,将其分为三段:左半段,循环段,平移段,分类讨论 r 落在哪段
O(m\log r)
*/
vector<ll>s,t;
inline int getch(ll p,int d){
if(d==0)
return str[p]-'a';
if(p<s[d])
return getch(p,d-1);
ll yiw=s[d]+k[d]-1;
if(p<=yiw)
return getch(t[d-1]-yiw+p,d-1);
return getch(p-yiw,d-1);
}
inline ll ask(ll r,int d,int x){
if(d==0)
return pr[x][r];
if(s[d]>r)
return ask(r,d-1,x);
ll yiw=s[d]+k[d]-1;
ll ad=(1ll<<d-1)*pr[x][l];
if(r<=yiw)
return pre[x][d][r-t[d-1]]+ad;
return ask(r-yiw,d-1,x)+pre[x][d][k[d]]+ad;
}
inline ll ask(ll r,int x){
if(r==0)
return 0;
int i;
for(i=0;t[i]<r;i++);
return ask(r,i,x);
}
int main(){
// freopen("data_C1.in","r",stdin);
// freopen("data_C1.out","w",stdout);
l=readstr(str);
n=read(),m=read();
for(int i=1;i<=l;i++)
for(int j=0;j<26;j++)
pr[j][i]=pr[j][i-1]+(str[i]==(j+'a'));
s.push_back(1),t.push_back(l);
for(int i=1;i<=n;i++)
k[i]=read();
for(int i=1;t.back()<1e18&&i<=60;i++){
ll x=t.back();
s.push_back(x+1),t.push_back(x*2);
}
for(int i=1;i<=60&&i<t.size();i++){
k[i]%=t[i-1];
for(int j=1;j<=k[i];j++){
int ch=getch(t[i-1]-k[i]+j,i-1);
for(int c=0;c<26;c++)
pre[c][i][j]=pre[c][i][j-1]+(c==ch);
}
}
while(m--){
ll l=read(),r=read(),x=getc()-'a';
write(ask(r,x)-ask(l-1,x)),putc('\n');
}
flush();
}
再见 qwq~

浙公网安备 33010602011771号