https://vjudge.net/problem/HDU-5685
题意:给一个公式 求字符串的hash值
然后给你一个完整字符串 a b 两点 然后输出a b子串的hash值
思路:子串, 有公式 ,很容易想到前缀积 因为利用前缀积可以表示任意一个子串
但是乘法,还累乘 肯定爆 所以我们只能保存mod后的值
现在有了pre【】 求a b子串 原本就是用 b/(a - 1) % mod 得到结果, 但因为以上因素
引入费马小定律 x是任意整数, p是一个质数(2,3,5,7,11,13)
x^(p-1) % p == 1 % p
推出 x^(p-2) %p == x^(-1) %p
即x^(p-2) 等价于 x^(-1)
再回来看 b/(a - 1) % mod 不就是 【(b%mod)*((a-1)%mod)】%mod
可以发现(b%mod)等于pre【b】 (a-1)%mod 等于 pre【a - 1】 等于pre【a - 1】的(p - 2) 次方
直接快速幂
//因为要问子串的的hash值
//先求前缀积 但是数很大,前缀积显然只能存下%9973后得值
//但有:(A/B)%M=(A%M*(B^-1%M))%M,A%M显然就是pre[A],B的逆对M取余就是qpow(B,M-2,M),快速幂模之即可
#include<iostream>
#include<cstring>
#include<cmath>
#include<string>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<functional>
using namespace std;
#define inf 0x3f3f3f3f
#define pi acos(-1.0)
#define LL long long
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define mem(a, b) memset(a, b, sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mod 9973
//#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);
const int maxn = 1e5 + 100;
int pre[maxn];
int qpow(int a, int b) {
int res = 1;
int temp = a;
while (b) {
if (b & 1) {
res *= temp;
res %= mod;
}
temp *= temp;
temp %= mod;
b >>= 1;
}
return res;
}
int main() {
ios;
int n;
while (cin >> n) {
string s;
cin >> s;
pre[0] = 1;
for (int i = 0; i < s.size(); ++i) {
pre[i + 1] = pre[i] * int(s[i] - 28) % mod;
}
int a, b;
while (n--) {
cin >> a >> b;
//b/(a - 1) % mod
//转化成(pre【b】* (a - 1)的p-2次方%mod)%mod
int ans = pre[b] * qpow(pre[a - 1], mod - 2) % mod;
cout << ans << endl;
}
}
return 0;
}