度熊手上有一本字典存储了大量的单词,有一次,他把所有单词组成了一个很长很长的字符串。现在麻烦来了,他忘记了原来的字符串都是什么,神奇的是他竟然记得原来那些字符串的哈希值。一个字符串的哈希值,由以下公式计算得到:
H(s)=∏i≤len(s)i=1(Si−28) (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; }
以上。