[hash+随机] 2017 计蒜之道初赛第五场UCloud 的安全秘钥

题意

给出一个长度为 n 的串 s,每次询问求给出串t,求 s 的子串中与 t 近似匹配 的个数。
定义 ab 近似匹配
1.a=b,即 a 串和 b 串长度相等。
2.对于每种数字 xxa 中出现的次数等于 xb 中出现的次数。
n50000,|t|100000

题解

我们给每个数随机一个权值,两个串近似匹配可以通过哈希 O(1) 判断,然后就可以做到 O(nm) 了。
怎么优化呢?可以发现所有t的长度最多只可能有 |t| 种.
然后对于每个长度,先把s的这个长度的所以子串hash值插到map里,然后进行询问。
这样复杂度是 O(n|t|) 的。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<tr1/unordered_map>
#include<algorithm>
using namespace std;
using namespace std::tr1;
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
    char ch=gc(); int res=0,ff=1;
    while(!('0'<=ch&&ch<='9')) ch=='-'?ff=-1:0, ch=gc();
    while('0'<=ch&&ch<='9') res=(res<<3)+(res<<1)+ch-'0', ch=gc();
    return res*ff;
}
const int maxn=100005;
typedef unsigned long long ull;
vector<int> id[maxn];
int n,Q,ans[maxn];
ull v_rnd[maxn],q[maxn],s[maxn];
ull getrand(){ return (((((ull)rand())<<16)+(rand()<<1)+(rand()&1))<<31)+(((ull)rand())<<16)+(rand()<<1)+(rand()&1); }

unordered_map <ull,int> mp;
void Pre(int len){
    mp.clear();
    for(int i=len;i<=n;i++){
        if(mp.find(s[i]^s[i-len])==mp.end()) mp[s[i]^s[i-len]]=0;
        mp[s[i]^s[i-len]]++;
    }
}
int Solve(ull x){
    if(mp.find(x)==mp.end()) return 0;
    return mp[x];
}
int main(){
    srand(19260817);
    n=getint();
    for(int i=1;i<=n;i++) v_rnd[i]=getrand();
    for(int i=1;i<=n;i++) s[i]=s[i-1]^(v_rnd[getint()]);
    Q=getint();
    for(int i=1;i<=Q;i++){
        int t=getint(); id[t].push_back(i);
        for(int j=1;j<=t;j++) q[i]^=v_rnd[getint()];
    }
    for(int i=1;i<=n;i++) if(!id[i].empty()){
        int sz=id[i].size();
        Pre(i);
        for(int j=0;j<=sz-1;j++) ans[id[i][j]]=Solve(q[id[i][j]]);
    }
    for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值