Problem A

度熊手上有一本字典存储了大量的单词,有一次,他把所有单词组成了一个很长很长的字符串。现在麻烦来了,他忘记了原来的字符串都是什么,神奇的是他竟然记得原来那些字符串的哈希值。一个字符串的哈希值,由以下公式计算得到: 
H(s)=ilen(s)i=1(Si28) (mod 9973)H(s)=∏i=1i≤len(s)(Si−28) (mod 9973) 
SiSi代表 S[i] 字符的 ASCII 码。 
请帮助度熊计算大字符串中任意一段的哈希值是多少。

······

题意大概就是给你多个案例,每组数据开头一个n,表示n组数据,然后一个字符串s。

首先先理解这个公式,由题意可知s的每一位上字母都代表一个数,字符串i位的哈希值就等于从第1位乘到i位,即 i!mod 9973.(用sum[i]代替)

要求a~b位就等于求   sum[b]/sum[(a-1)] mod 9973;

显然,我们要先求inv(sum[(a-1)])=x;

结果就等于:sum[b]*x mod 9973,代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll inv[1000000];                   //三个数组,inv打表1~100006对9973的逆元
ll sum[1000000];                   //sum存第i位的哈希 
ll re[1000000];                    //re存的i位的逆元
int p=9973;
int main()
{
    inv[1]=1;
    for(int i=2;i<=100006;i++)        //先打表,把1~1000000对9973的逆元算出来 
        inv[i]=(p-p/i)*inv[p%i]%p;
    int n;
    while(~scanf("%d",&n))
    {
        char s[100006];
        scanf("%s",s+1);
        re[0]=sum[0]=1;
        for(int i=1;s[i]!=0;++i)
        {
            sum[i]=(sum[i-1]*(s[i]-28))%p;
            re[i]=inv[sum[i]];
        }
        while(n--)
        {
            ll a,b;
            cin>>a>>b;
            ll ans=sum[b]*re[a-1]%p;
            cout<<ans<<endl;
        }
    }
    return 0;
}

 

以上。

 

posted @ 2019-08-14 22:11  Luoha  阅读(247)  评论(0编辑  收藏  举报