题目大意:有$n$个数,每个数为$s_i$,两个操作:
- $1;l;r;x:$表示将区间$[l,r]$内的数加上$x$
- $2;l;r;p:$表示求$s_l^{s_{l+1}^{^{s_{l+2}dots}}}mod p$直到$s_r$
题解:区间加可以通过树状数组维护,考虑操作二,由扩展欧拉定理可得:
$$
a^bequiv
egin{cases}
a^{bmod{varphi(p)}} &(a,b)=1\
a^b &(a,b)
ot=1,b<varphi(p)\
a^{bmod{varphi(p)}+varphi(p)} &(a,p)
ot=1,bgeqslantvarphi(p)
end{cases}
pmod{p}
$$
$varphi$函数最多递归$O(log_2)$层就会变成$1$,可以暴力算
注意要在快速幂里面记录取过模,若取过,最后要加上一个$p$
卡点:没注意快速幂中部分,没有开$long;long$
C++ Code:
#include <cstdio> #include <cctype> namespace __IO { namespace R { int x, ch; inline int read() { while (isspace(ch = getchar())); for (x = ch & 15; isdigit(ch = getchar()); ) x = x * 10 + (ch & 15); return x; } } } using __IO::R::read; #define maxn 500010 int n, m; namespace BIT { long long Tr[maxn], res; inline void add(int p, const int x) {for (; p <= n; p += p & -p) Tr[p] += x;} inline long long ask(int p) {for (res = 0; p; p &= p - 1) res += Tr[p]; return res;} } namespace Math { const int N = 2e7 + 1; int phi[N], plist[N], ptot; bool notp[N]; void sieve() { phi[1] = 1; for (int i = 2; i < N; i++) { if (!notp[i]) phi[plist[ptot++] = i] = i - 1; for (int j = 0, t; j < ptot && (t = i * plist[j]) < N; j++) { notp[t] = true; if (i % plist[j] == 0) { phi[t] = phi[i] * plist[j]; break; } phi[t] = phi[i] * phi[plist[j]]; } } } inline long long pw(long long base, long long p, const int mod) { long long res = 1, b = base, tmp = 0; if (b >= mod && p) tmp = mod, b %= mod; for (; p; p >>= 1) { if (p & 1) { res = res * b; if (res >= mod) tmp = mod, res %= mod; } b = b * b; if (b >= mod && p >> 1) tmp = mod, b %= mod; } return res + tmp; } } using Math::phi; long long query(const int l, const int r, const int p) { const long long x = BIT::ask(l); if (!x) return 0; if (x % p == 0) return p; if (l == r) return x >= p ? x % p + p : x; return Math::pw(x, query(l + 1, r, phi[p]), p); } int main() { Math::sieve(); n = read(), m = read(); for (int i = 1, last = 0, x; i <= n; ++i) { x = read(); BIT::add(i, x - last); last = x; } while (m --> 0) { int op = read(), l = read(), r = read(), x = read(); if (op == 1) BIT::add(l, x), BIT::add(r + 1, -x); else printf("%lld ", query(l, r, x) % x); } return 0; }