度熊手上有一本字典存储了大量的单词,有一次,他把所有单词组成了一个很长很长的字符串。现在麻烦来了,他忘记了原来的字符串都是什么,神奇的是他竟然记得原来那些字符串的哈希值。一个字符串的哈希值,由以下公式计算得到:
H(s)=∏i≤len(s)i=1(Si−28) (mod 9973) H(s)=∏i=1i≤len(s)(Si−28) (mod 9973)
Si Si代表 S[i] 字符的 ASCII 码。
请帮助度熊计算大字符串中任意一段的哈希值是多少。 Input
多组测试数据,每组测试数据第一行是一个正整数
N
N,代表询问的次数,第二行一个字符串,代表题目中的大字符串,接下来
N
N行,每行包含两个正整数
a
a和
b
b,代表询问的起始位置以及终止位置。
1≤N≤1,000 1≤N≤1,000
1≤len(string)≤100,000 1≤len(string)≤100,000
1≤a,b≤len(string) 1≤a,b≤len(string)
Output
对于每一个询问,输出一个整数值,代表大字符串从
a
a 位到
b
b 位的子串的哈希值。
Sample Input
Sample Output
H(s)=∏i≤len(s)i=1(Si−28) (mod 9973) H(s)=∏i=1i≤len(s)(Si−28) (mod 9973)
Si Si代表 S[i] 字符的 ASCII 码。
请帮助度熊计算大字符串中任意一段的哈希值是多少。 Input
1≤N≤1,000 1≤N≤1,000
1≤len(string)≤100,000 1≤len(string)≤100,000
1≤a,b≤len(string) 1≤a,b≤len(string)
2 ACMlove2015 1 11 8 10 1 testMessage 1 1
6891924088
中文题意不解释,思路:实际上就是 求h[右]/h[左-1]%Mod 的值, 因为是除法,用到逆元。
逆元,这里用到了一个费马小定理的知识 a^(p-1) == 1(%p) gcd(a,p)=1; 即gcd(a,p)=1的情况下,a*a^(p-2) = 1 , 即 a的逆元为a^(p-2)
(a/b)%Mod == a*(b的逆元)%Mod
计算b的逆元 b^(p-2) 由于p很大,所以用到了快速幂的知识。
#include<stdio.h>
#include<string.h>
#define Mod 9973
char str[100005];
int pre[100005];
int Quik(int a, int b)//快速幂 算a^b
{
int ans = 1;
while(b)
{
if(b & 1)//是奇数
ans = (ans*a)%Mod;
a = (a*a)%Mod;
b /= 2;
}
return ans%Mod;///这里记得要再一次%Mod 不然会错
}
int main()
{
int t;
while(~scanf("%d",&t))
{
memset(pre,0,sizeof pre);
scanf("%s",str);
int len = strlen(str);
pre[0] = 1;
for(int i = 1; i <= len; i++)
{
pre[i] = pre[i-1]*(str[i-1]-28);
pre[i] %= Mod;
}
while(t--)
{
int left,right;
scanf("%d%d",&left,&right);
printf("%d\n",(pre[right]*Quik(pre[left-1],Mod-2))%Mod);
}
}
}