1. 程式人生 > >[洛谷P4118][Ynoi2016]炸脖龍I([洛谷P3934]Nephren Ruq Insania)

[洛谷P4118][Ynoi2016]炸脖龍I([洛谷P3934]Nephren Ruq Insania)

題目大意:有$n$個數,每個數為$s_i$,兩個操作:

  1. $1\;l\;r\;x:$表示將區間$[l,r]$內的數加上$x$
  2. $2\;l\;r\;p:$表示求$s_l^{s_{l+1}^{^{s_{l+2}\dots}}}\bmod p$直到$s_r$

題解:區間加可以通過樹狀陣列維護,考慮操作二,由擴充套件尤拉定理可得:
$$
a^b\equiv
\begin{cases}
a^{b\bmod{\varphi(p)}} &(a,b)=1\\
a^b &(a,b)\not=1,b<\varphi(p)\\
a^{b\bmod{\varphi(p)}+\varphi(p)} &(a,p)\not=1,b\geqslant\varphi(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\n", query(l, r, x) % x);
	}
	return 0;
}