专栏文章
Ciallo~(∠・ω< )⌒★
P9576题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mip94itr
- 此快照首次捕获于
- 2025/12/03 08:11 3 个月前
- 此快照最后确认于
- 2025/12/03 08:11 3 个月前
ac 祭!
巡厨不请自来~(∠・ω< )⌒★
以下 ,,数组下标从 开始。
要我们求把 取一段前缀 和一段后缀 ,满足 。求将这两段拼起来后的串中 的出现次数之和。
对于完整存在于一段前缀或后缀中的 ,我们可以简单求出数量。具体而言,若 ,对答案的贡献是 。
那么剩下的就是 横跨两段的情况。
枚举 在 中的长度 ,同时得到 在 中的长度 。
令所有可以作为 前 位左端点的位置的集合为 ,可以作为 后 位右端点的位置的集合为 。那么对于 和 ,如果满足 ,则贡献一种方案。
此时问题转化为二维偏序,考虑用树状数组维护。
注意到随着 增大, 和 的变化总数为 级别。利用哈希值在每个位置上二分可以求出这个位置往左或往右最多与 的前或后若干位相同。然后简单维护修改即可。
CPP#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
using namespace std;
const int N = 400100;
const ull base = 29;
string s,t;
int n,m,ans;
int maxa[N],maxb[N];
vector <int> vea[N],veb[N];
ull p[N],hs[N],ht[N];
int gets(int l,int r){
if(l==0) return hs[r];
return hs[r]-hs[l-1]*p[r-l+1];
}
int gett(int l,int r){
if(l==0) return ht[r];
return ht[r]-ht[l-1]*p[r-l+1];
}
struct BIT{
int tree[N];
int lowbit(int x){
return x & (-x);
}
inline void updata(int x,int d){
int u=x;
while(u<=n){
tree[u]+=d;
u+=lowbit(u);
}
return;
}
int query(int x){
int u=x,ans=0;
while(u>0){
ans+=tree[u];
u-=lowbit(u);
}
return ans;
}
};
BIT A,B;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin>>s>>t;
n=s.size(),m=t.size();
p[0]=1,hs[0]=s[0]-'a'+1,ht[0]=t[0]-'a'+1;
for(int i=1;i<=n+2;i++) p[i]=p[i-1]*base;
for(int i=1;i<n;i++) hs[i]=hs[i-1]*base+(s[i]-'a'+1);
for(int i=1;i<m;i++) ht[i]=ht[i-1]*base+(t[i]-'a'+1);
for(int i=0;i<=n-m;i++){
if(gets(i,i+m-1)==ht[m-1]) ans+=(1+n-i-m)*(n-i-m)/2+i*(i+1)/2;
}
for(int i=0;i<n;i++){
int l=1,r=max(m,n-i);
while(l<=r){
int mid=l+r>>1;
if(gets(i,i+mid-1)==gett(0,mid-1)) maxa[i]=mid,l=mid+1;
else r=mid-1;
}
l=1,r=max(m,i+1);
while(l<=r){
int mid=l+r>>1;
if(gets(i-mid+1,i)==gett(m-mid,m-1)) maxb[i]=mid,l=mid+1;
else r=mid-1;
}
vea[maxa[i]].push_back(i);
veb[maxb[i]].push_back(i);
}
for(int i=0;i<n;i++) A.updata(i+1,1);
for(int i=0;i<veb[m].size();i++) veb[m-1].push_back(veb[m][i]);
int cnt=0;
for(int i=1;i<m;i++){
int j=m-i;
for(int k=0;k<vea[i-1].size();k++){
int u=vea[i-1][k];
if(u+m<=n) cnt-=(B.query(n)-B.query(u+m));
A.updata(u+1,-1);
}
for(int k=0;k<veb[j].size();k++){
int u=veb[j][k];
cnt+=A.query(u-m+1);
B.updata(u+1,1);
}
ans+=cnt;
}
cout<<ans;
return 0;
}
但是魔女的夜宴真的很好玩啊。
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...