Problem A
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2241 Accepted Submission(s): 989
Problem Description
度熊手上有一本字典存储了大量的单词,有一次,他把所有单词组成了一个很长很长的字符串。现在麻烦来了,他忘记了原来的字符串都是什么,神奇的是他竟然记得原来那些字符串的哈希值。一个字符串的哈希值,由以下公式计算得到:
H(s)=∏i≤len(s)i=1(Si−28) (mod 9973) 位的子串的哈希值。
H(s)=∏i≤len(s)i=1(Si−28) (mod 9973) 位的子串的哈希值。
Sample Input
2
ACMlove2015
1 11
8 10
1
testMessage
1 1
Sample Output
6891
9240
88
Source
Recommend
liuyiding
题解:求s[a]到s[b]的哈希值之积,
注意∏符号,求积。若直接求a到b会超时,,想到求1到b的前缀积除以1到a的前缀积,因为取模不满足相除,这里通用求逆元来解决
解法一:(直接求逆元,打表)
解法二:(用扩展欧几里得算法)
两个代码放在一起了
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std;
const int mod = 9973;
int N;
int H[100000+5];
int inv[10000];
string s;
int a,b;
int exgcd(int A,int B,int &x,int &y){
if(B==0){
x=1;
y=0;
return A;
}
int d = exgcd(B,A%B,x,y);
int temp=x;
x=y;
y=temp-A/B*y;
return d;
}
int Inv(int A,int B){
int x,y;
int d = exgcd(A,B,x,y);
x=(x%mod+mod)%mod;
return x;
}
int main()
{
inv[1]=1;
//逆元打表
for(int i=2;i<10000;i++){
inv[i] =inv[mod%i]*(mod-mod/i)%mod;
}
while(scanf("%d",&N)!=EOF){
cin >> s;
int len=s.length();
H[0]=1;
for(int i=1;i<=len;i++){
H[i]=(H[i-1]%mod)*((s[i-1]-28)%mod)%mod;
}
for(int i=1;i<=N;i++){
scanf("%d %d",&a,&b);
int sum=1,sum1=1,ans=1;
ans=H[b];
//解法一从表中求得逆元
sum1=inv[H[a-1]]%mod;
//exgcd得到
sum=Inv(H[a-1],mod);
printf("%d\n",((ans%mod)*(sum%mod))%mod);
}
}
return 0;
}