Problem A ( 乘法逆元 )
题意:就是给一串数,给一个边界left和right,求从left乘到right的值%9973是多少。
思路:维护一个前缀乘积prev,要求[a, b]的hash,只要(prev[b]*inv(prev[a-1]))%mod即可
因为前缀乘积要mod9973,所以一定小于9973,而且9973是素数,gcd(prev[a-1],9973)一定等于1 。可以用exgcd求,也可以用费马小定理求逆元。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char a[100005];
long long d[100005];
long long n;
long long l,r;
ll exgcd( ll a, ll b, ll &x, ll &y )
{
if ( b==0 ) {
x = 1;
y = 0;
return a;
}
ll re = exgcd(b,a%b,y,x);
y -= x*(a/b);
return re;
}
ll getni( ll a, ll b )
{
ll x,y,gcd=exgcd(a,b,x,y);
if ( gcd==1 ) {
if ( x<0 ) return x%b+b;
else return x%b;
}
else return -1;
}
int main()
{
while ( cin>>n ) {
scanf("%s",a+1);
long long len = strlen(a+1);
d[0] = 1;
for ( int i=1; i<=len; i++ ) {
d[i] = (d[i-1]*(a[i]-28))%9973;
}
while ( n-- ) {
scanf("%lld %lld",&l,&r);
ll a=d[l-1],b=9973;
ll x = getni(a,b);
printf("%lld\n",(d[r]*x)%9973 );
}
}
return 0;
}