链接:https://ac.nowcoder.com/acm/contest/9984/B
来源:牛客网
题目描述
众所周知,武辰延很喜欢字符串。
这天,他对着两个字符串 s 和 t 发呆,他发现这两个串的前缀有很多相似的地方,s 的两个前缀连接起来竟也是 t 的前缀。
武辰延想知道有多少对 s 的非空前缀连接起来是 t 的前缀。
形式化地讲,我们把 si看作字符串 s 长度为 i 的前缀。
对于一对前缀 (si ,sj) (允许 i=j)而言,当满足 si+sj=ti+j时,我们认为这两个 s 的前缀拼接后等于 t 的一个前缀。
两对 s 的前缀 (si,sj) 与si′,sj′) 不同当且仅当 i!=i′或 j!=j′。
输入描述:
第一行一个字符串 s 。
第二行一个字符串 t 。
其中 11≤∣s∣,∣t∣≤1e5 ,只包含小写字母。
输出描述:
输出一行一个整数,表示满足条件的前缀的对数。
示例1
输入
aab
aaa
输出
3
思路
我们从1带lent来枚举si,然后二分找sj的最大长度,每次累加最大长度就是答案,判断行不行用进制hash
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+5;
const double esp=1e-6;
const ll mod=1e9+7;
const int base = 233;
int n,m,op;
char s[N],t[N];
ull h1[N],h2[N],p[N];
ll qpow(ll a,ll b){
ll ans=1,base=a;
while(b){
if(b&1) ans=ans*base%mod;
base=base*base%mod;
b>>=1;
}
return ans;
}
ull get_hash(ull h[],int len,int l,int r){
if(r>len) return 0;
return h[r]-h[l-1]*p[r-l+1];
}
void solve(){
scanf("%s %s",s+1,t+1);
int l1=strlen(s+1),l2=strlen(t+1);
p[0]=1;
for(int i=1;i<=l1;i++){
h1[i]=h1[i-1]*base+s[i];
p[i]=p[i-1]*base;
}
for(int i=1;i<=l2;i++){
h2[i]=h2[i-1]*base+t[i];
if(i>=l1) p[i]=p[i-1]*base;
}
ll res = 0;
for(int i=1;i<=l2;i++){
if(s[i]!=t[i]) break;
if(s[1]!=t[i+1]) continue;
int l=1,r=l1;
while(l<r){
int mid=(l+r+1)/2;
ull t1=get_hash(h1,l1,1,mid);
ull t2=get_hash(h2,l2,i+1,i+mid);
if(t1==t2) l=mid;
else r=mid-1;
}
res+=l;
}
printf("%lld",res);
}
int main(){
int Case=1;
//init();
//scanf("%d",&Case);
while(Case--){
solve();
}
return 0;
}