zoukankan      html  css  js  c++  java
  • 【JZOJ5462】好文章【哈希】

    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/5462
    题目图片:
    http://wx4.sinaimg.cn/mw690/0060lm7Tly1fwena030iwj30j70ba74m.jpg
    http://wx2.sinaimg.cn/mw690/0060lm7Tly1fwena02ec5j30ja0eb74j.jpg
    给出一个长度为nn的小写字母组成的字符串,求其中有几个不同的(断句)长度为mm的子串。


    思路:

    50分做法:

    1mn20001≤m≤n≤2000
    枚举子串开始的位置,再将接下来的mm位扔进TrieTrie里,记录答案即可。
    时间复杂度O(n2log)O(n^2log)
    代码

    100分做法:

    1mn2000001≤m≤n≤200000
    字符串HASHHASH
    这道题很诡异的卡单哈希,所以得用双哈希。
    我们假设有一个字符串是这样的:

    • c[]=iamjuruoc[]=iamjuruo

    那么我们可以取出它前面的ii位。

    • s[1]=c[1]=is[1]=c[1]=i
    • s[2]=s[1]+c[2]=ias[2]=s[1]+c[2]=ia
    • s[3]=s[2]+c[3]=iams[3]=s[2]+c[3]=iam
    • s[4]=s[3]+c[4]=iamjs[4]=s[3]+c[4]=iamj
    • ............
    • s[8]=s[7]+c[8]=iamjuruos[8]=s[7]+c[8]=iamjuruo

    那么如果我们呢要取出这个字符串的第llrr位,那么应该怎么取呢?
    我们假设这个字符串是一个十进制数字。

    • c[]=12345678c[]=12345678
    • s[1]=1s[1]=1
    • s[2]=12s[2]=12
    • s[3]=123s[3]=123
    • ............
    • s[8]=12345678s[8]=12345678

    那么如果我们要取出这个数字串的第3366位,那么自然就是:
    ans=s[6]s[31]×106(31)ans=s[6]-s[3-1]\times 10^{6-(3-1)}
    那么我们可以进一步得到,如果我们要取出这个字符串的第llrr位,那么就是
    ans=s[r]s[l1]×10r(l1)ans=s[r]-s[l-1]\times 10^{r-(l-1)}
    所以,如果我们把这个字符串看成一个BASE进制的数字串,就可以按照上述公式求第llrr位。
    那么就有:
    ans=s[r]s[l1]×BASE r(l1)ans=s[r]-s[l-1]\times BASE^{\ r-(l-1)}
    所以,哈希就可以这样用了。
    时间复杂度:O(nlog)O(nlog)


    代码:

    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <iostream>
    #define MOD1 290182597
    #define MOD2 163227661
    #define BASE1 3769
    #define BASE2 9439
    #define N 200100
    #define ll long long
    #define mp make_pair
    using namespace std;
    
    int n,m,pow1[N],pow2[N],hash1[N],hash2[N],ans;
    char c[N];
    map<pair<int,int>,int> p;
    
    ll find1(int l,int r)
    {
    	return (hash1[r]-(ll)hash1[l-1]*pow1[r-l+1]%MOD1+MOD1)%MOD1;   //上述公式
    }
    
    ll find2(int l,int r)
    {
    	return (hash2[r]-(ll)hash2[l-1]*pow2[r-l+1]%MOD2+MOD2)%MOD2; 
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	cin>>c+1;
    	pow1[0]=1;
    	pow2[0]=1;
    	for (int i=1;i<=n;i++)
    	{
    		pow1[i]=((ll)pow1[i-1]*BASE1)%MOD1;
    		pow2[i]=((ll)pow2[i-1]*BASE2)%MOD2;  //取出BASE的x次方
    		hash1[i]=((ll)hash1[i-1]*BASE1%MOD1+c[i]-'a'+1)%MOD1;
    		hash2[i]=((ll)hash2[i-1]*BASE2%MOD2+c[i]-'a'+1)%MOD2;  //HASH函数
    	}
    	ll x,y;
    	for (int i=1;i<=n-m+1;i++)
    	{
    		x=find1(i,i+m-1);
    		y=find2(i,i+m-1);
    		if (!p[mp(x,y)]) ans++;  //没有出现过
    		p[mp(x,y)]=1;
    	}
    	printf("%d\n",ans);
    	return 0;
    }
    
  • 相关阅读:
    Codeforces 877 C. Slava and tanks
    Codeforces 877 D. Olya and Energy Drinks
    2017 10.25 NOIP模拟赛
    2017 国庆湖南 Day1
    UVA 12113 Overlapping Squares
    学大伟业 国庆Day2
    51nod 1629 B君的圆锥
    51nod 1381 硬币游戏
    [JSOI2010]满汉全席
    学大伟业 2017 国庆 Day1
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998512.html
Copyright © 2011-2022 走看看