/** 题意:B,P,L,N,分别表示进制,mod,数组的个数,操作数 做法:树状数组 欧几里得 每个数加入到数组Tree的数是 B^(L-i) 用树状数组进行维护前缀和,然后求一段区间的数,除以B^(L-j) 因为(前缀和/B^(L-j)) 很大不好计算,所以就用乘法逆元 (k是a关于p的乘法的逆元) a*k≡1 (mod p) === (a/b)mod p (b关于p的乘法的逆元) PS(当我们要求(a/b) mod p的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元。 我们可以通过求b关于p的乘法逆元k,将a乘上k再模p,即(a*k) mod p。其结果与(a/b) mod p等价。) **/ #include <iostream> #include <algorithm> #include <string.h> #include <cmath> #include <stdio.h> #define maxn 200000 + 10 using namespace std; long long Tree[maxn]; long long mmap[maxn]; ///逆元 long long _next[maxn]; /// 次方 long long extend_gcd(long long a,long long b,long long &x,long long &y) { if(a == 0 && b == 0) return -1; if(b == 0) { x = 1; y = 0; return a; } long long d = extend_gcd(b,a%b,y,x); y -= a/b*x; return d; } long long mod_reverse(long long a,long long n) { long long x,y; long long d = extend_gcd(a,n,x,y); if(d == 1) return (x%n+n)%n; else return -1; } long long B,P,L,N; int lowbit(int x) { return x&(-x); } void add(int x, long long value) { for(int i = x; i <= L; i += lowbit(i)) { Tree[i] = ((Tree[i] + value) % P + P) % P; } } long long getsum(int x) { long long sum =0; for(int i=x; i; i -= lowbit(i)) sum = ((sum + Tree[i])%P + P)%P; return sum; } int main() { //freopen("in.txt","r",stdin); while(~scanf("%lld %lld %lld %lld",&B,&P,&L,&N)) { if(B == 0 && P == 0 && L == 0 &&N == 0) break; memset(Tree,0,sizeof(Tree)); memset(mmap,0,sizeof(mmap)); memset(_next,0,sizeof(_next)); int tmp = 1; mmap[L] = 1; _next[L] = 1; for(int i=L-1; i>=1; i--) { tmp = (tmp *B) %P; mmap[i] = mod_reverse(tmp,P); _next[i] = tmp; } int u,v; char ch[10]; for(int i=1; i<=N; i++) { scanf("%s %d %d",ch,&u,&v); //cout<<ch<<" "<<u<<" "<<v<<endl; if(ch[0] == 'E') { long long ans = (getsum(u) - getsum(u-1)); ans -= v*_next[u]; add(u,-ans); } else if(ch[0] == 'H') { long long ans = ((getsum(v) - getsum(u-1))%P +P)%P; //cout<<"ans = "<<ans<<endl; ans = (ans *mmap[v])%P; printf("%lld ",ans); } } printf("- "); } return 0; }