「TAOI-2」Ciallo~(∠・ω< )⌒★ 题解
手玩了一个小时终于做出来了,这不得写一篇题解记录一下??
下面设
考虑分类讨论:
如果
我们也可以选定一个子串
例如 ciaohallo
要变成 ciallo
就可以选取前缀 cia
和后缀 llo
,它们拼在一起就是我们要得到的字符串。值得注意的是,为了避免掉与上一种情况出现重复计算,我们需要满足 oha
这一段字符。
但是怎么计算满足上述条件的
为什么是对的?我们来看一下这张图:
图中第一行是
我们可以考虑 ABA
,ABAA
,ABAAB
,ABAABA
,即重合部分的长度加一
综上所述,对于每一个
可是暴力找是
然后就可以愉快地打出代码了:
#include<bits/stdc++.h>
#define Q(id,x,y,flag) query(1,1,id,x,y,flag)
using namespace std;
const int MAXN=4e5+5;
const unsigned long long base=179;
int n,m;
char a[MAXN],b[MAXN];
unsigned long long mul[MAXN],Hash1[MAXN],Hash2[MAXN];
int p[MAXN],q[MAXN];
struct node
{
long long sum;
int num;//sum表示和,num表示个数
}T[MAXN<<2];
void pushup(int x){ T[x].num=T[x<<1].num+T[x<<1|1].num,T[x].sum=T[x<<1].sum+T[x<<1|1].sum; }
void change_tree(int x,int l,int r,int k)
{
if(l>r) return;
if(l==r)
{
T[x].sum+=l,T[x].num++;
return;
}
int mid=(l+r)/2;
if(k<=mid) change_tree(x<<1,l,mid,k);
else change_tree(x<<1|1,mid+1,r,k);
pushup(x);
}
long long query(int x,int l,int r,int L,int R,int flag)
{
if(L>R) return 0;
if(L<=l&&r<=R)
{
if(!flag) return T[x].sum;
return T[x].num;
}
int mid=(l+r)/2;
long long res=0;
if(L<=mid) res+=query(x<<1,l,mid,L,R,flag);
if(R>mid) res+=query(x<<1|1,mid+1,r,L,R,flag);
return res;
}
long long solve(int x){ return 1ll*x*(x+1)/2; }
int main()
{
cin>>(a+1)>>(b+1);
n=strlen(a+1),m=strlen(b+1);
mul[0]=1;
for(int i=1;i<=n;i++) Hash1[i]=Hash1[i-1]*base+a[i],mul[i]=mul[i-1]*base;//哈希预处理
for(int i=1;i<=m;i++) Hash2[i]=Hash2[i-1]*base+b[i];
for(int i=1;i<=n;i++)
{
if(a[i]!=b[1]) continue;
int l=1,r=min(n-i+1,m);
while(l<=r)//二分找最长公共前缀
{
int mid=(l+r)/2;
if(Hash1[i+mid-1]-Hash1[i-1]*mul[mid]==Hash2[mid]) p[i]=mid,l=mid+1;
else r=mid-1;
}
p[i]=min(p[i],m-1);
}
for(int i=n;i>=1;i--)
{
if(a[i]!=b[m]) continue;
int l=1,r=min(i,m);
while(l<=r)//同理找后缀
{
int mid=(l+r)/2;
if(Hash1[i]-Hash1[i-mid]*mul[mid]==Hash2[m]-Hash2[m-mid]*mul[mid]) q[i]=mid,l=mid+1;
else r=mid-1;
}
q[i]=min(q[i],m-1);
}
long long res=0;
for(int i=1;i<=n-m+1;i++)
{
if(Hash1[i+m-1]-Hash1[i-1]*mul[m]==Hash2[m]) res+=solve(i-1)+solve(n-i-m+1);//第一种情况
}
if(q[n]) change_tree(1,1,m-1,q[n]);
for(int i=n-m;i>=1;i--)//注意是逆序!!!!
{
if(p[i]) res+=Q(m-1,m-p[i],m-1,0)+Q(m-1,m-p[i],m-1,1)*(p[i]-m+1);
if(q[i+m-1]) change_tree(1,1,m-1,q[i+m-1]);//每次要记得更新线段树
}
cout<<res;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现