11/5/2018模拟 Problem C

题面

1326473-20181105173024551-595912735.jpg
1326473-20181105173028395-743362444.jpg

题解

我有特殊的哈希技巧

以到下一个相同字符的距离为值哈希, 如果不存在或在串外, 就是 \(|T| + 1\).

加入一个新字符 \(S_i\) 时, 同时修改它上一次出现时的值, 由 \(|T| + 1\) 修改为 \(i\).

详见代码.

代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define rep(i,l,r) for(register int i=(l);i<=(r);++i)
#define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
#define il inline
typedef double db;
typedef long long ll;
typedef unsigned long long ull;

//---------------------------------------
const int nsz=1e6+50,msz=1e5+50,base=1e5+3;
int n,m;
char s[nsz],t[msz];
il int tr(char c){return c-'a'+1;}
int nes[nsz],prs[nsz];
int net[msz],prt[msz];
ull hs=0,ht=0,pb[msz]{1};

void gene(char *s,int *ne,int *pr,int n){
    static int bot[30];
    rep(i,1,26)bot[i]=n+1;
    repdo(i,n,1){
        ne[i]=bot[tr(s[i-1])];
        bot[tr(s[i-1])]=i;
    }
    rep(i,1,26)bot[i]=0;
    rep(i,1,n){
        pr[i]=bot[tr(s[i-1])];
        bot[tr(s[i-1])]=i;
    }
}

void sol(){
    gene(s,nes,prs,n);
    gene(t,net,prt,m);
    rep(i,1,m){
        ht=ht*base+(net[i]==m+1?m+1:net[i]-i);
        hs=hs*base+(nes[i]>m?m+1:nes[i]-i);
        pb[i]=pb[i-1]*base;
    }
    if(hs==ht)cout<<1<<'\n';
    ull tmp;
    rep(i,m+1,n){//[i-m+1,i]
        tmp=(nes[i-m]>i-1?m+1:nes[i-m]-(i-m));
        hs=hs*base-tmp*pb[m];
        tmp=i-prs[i];
        if(tmp<m){
            hs-=(m+1-tmp)*pb[tmp];   //dynamically modify
        }
        hs+=m+1;
        if(hs==ht)cout<<i-m+1<<'\n';
    }
}

int main(){
//  freopen("c.in","r",stdin);
//  freopen("c.out","w",stdout);
    ios::sync_with_stdio(0),cin.tie(0);
    cin>>s>>t;
    n=strlen(s),m=strlen(t);
    if(n<m)return 0;
    sol();
    return 0;
}

转载于:https://www.cnblogs.com/ubospica/p/9910410.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值