Problem A
Problem Description
度熊手上有一本字典存储了大量的单词,有一次,他把所有单词组成了一个很长很长的字符串。现在麻烦来了,他忘记了原来的字符串都是什么,神奇的是他竟然记得原来那些字符串的哈希值。一个字符串的哈希值,由以下公式计算得到:
H(s)=∏i≤len(s)i=1(Si−28) (mod 9973)
Si代表 S[i] 字符的 ASCII 码。
请帮助度熊计算大字符串中任意一段的哈希值是多少。
Input
多组测试数据,每组测试数据第一行是一个正整数N,代表询问的次数,第二行一个字符串,代表题目中的大字符串,接下来N行,每行包含两个正整数a和b,代表询问的起始位置以及终止位置。
1≤N≤1,000
1≤len(string)≤100,000
1≤a,b≤len(string)
Output
对于每一个询问,输出一个整数值,代表大字符串从 a 位到 b 位的子串的哈希值。
Sample Input
2
ACMlove2015
1 11
8 10
1
testMessage
1 1
Sample Output
6891
9240
88
解题思路:
维护一个前缀积,求【a-b】的哈希值。就是求pre[b]乘上pre[a-1]的逆元。
逆元的含义:
转自:https://www.cnblogs.com/zzqc/p/7192436.html
首先说明逆元的概念,类似于倒数的性质。
方程ax≡1(mod p),的解称为a关于模p的逆,当gcd(a,p)==1(即a,p互质)时,方程有唯一解,否则无解。
对于一些题目会要求把结果MOD一个数,通常是一个较大的质数,对于加减乘法通过同余定理可以直接拆开计算,
但对于(a/b)%MOD这个式子,是不可以写成(a%MOD/b%MOD)%MOD的,但是可以写为(a*b-1)%MOD,其中b-1表示b的逆元。
知道了逆元的作用,接下来就是逆元的求法。
逆元的求法:
参考: https://blog.csdn.net/u013852115/article/details/82902009
费马小定理求逆元 O(logn):
const int mod = 1000000009;
long long quickpow(long long a, long long b) {
if (b < 0) return 0;
long long ret = 1;
a %= mod;
while(b) {
if (b & 1) ret = (ret * a) % mod;
b >>= 1;
a = (a * a) % mod;
}
return ret;
}
long long inv(long long a) {
return quickpow(a, mod - 2);
}
逆元线性筛 O(n):
const int mod = 1000000009;
const int maxn = 10005;
int inv[maxn];
inv[1] = 1;
for(int i = 2; i < 10000; i++)
inv[i] = inv[mod % i] * (mod - mod / i) % mod;
阶乘的逆元 O(logn+n):
inv[maxn]=mod_pow(fac[maxn],mod-2);
for(ll i=maxn-1;i>=0;i--)
inv[i]=(inv[i+1]*(i+1))%mod;
AC代码:
#include <cstdio>
#include <cstring>
const int maxn=1e5+20, mod=9973;
char str[maxn];
int prev[maxn], n, len;
int exgcd(int a, int b, int &x, int &y){
if (b==0){x=1; y=0; return a;}
int gcd=exgcd(b, a%b, y, x);
y-=(a/b)*x;
return gcd;
}
int inv(int a, int p){
int x, y, gcd=exgcd(a, p, x, y);
if (gcd==1) return (x%p+p)%p;
return -1;
}
int main(void){
while (scanf("%d", &n)==1 && n){
scanf("%s", str+1);
len=strlen(str+1);
prev[0]=1;
for (int i=1; i<=len; i++)
prev[i]=(prev[i-1]*(str[i]-28))%mod;
int a, b;
while (n--){
scanf("%d%d", &a, &b);
printf("%d\n", (prev[b]*inv(prev[a-1], mod))%mod);
}
}
return 0;
}