Description
给定序列 a=(a1,a2,⋯ ,an)a=(a_1,a_2,\cdots,a_n)a=(a1,a2,⋯,an).
有 mmm 个操作,分以下两种:
- modify(l,r,k)\operatorname{modify}(l,r,k)modify(l,r,k):对每个 i∈[l,r]i \in [l,r]i∈[l,r] 执行 ai←ai+ka_i \leftarrow a_i+kai←ai+k
- query(l,r,p)\operatorname{query}(l,r,p)query(l,r,p):定义 f(l,l)=alf(l,l)=a_lf(l,l)=al,f(l,r)=alf(l+1,r) (l<r)f(l,r)=a_l^{f(l+1,r)} \;(l < r)f(l,r)=alf(l+1,r)(l<r),求 f(l,r) mod pf(l,r) \bmod pf(l,r)modp。
Limitations
1≤n,m≤5×1051 \le n,m \le 5\times 10^51≤n,m≤5×105
1≤ai≤2×1091 \le a_i \le 2\times 10^91≤ai≤2×109
1≤p≤2×1071 \le p \le 2\times 10^71≤p≤2×107
0≤k≤2×1090 \le k \le 2\times 10^90≤k≤2×109
2.5s,512MB2.5\text{s},512\text{MB}2.5s,512MB
Solution
连幂运算不满足结合律,不能线段树维护。
考虑扩展欧拉定理:
ab≡ab mod ϕ(p)+ϕ(p)×[b≥ϕ(p)](modp)a^b \equiv a^{b \bmod \phi(p)+\phi(p)\times[b \ge \phi(p)]} \pmod pab≡abmodϕ(p)+ϕ(p)×[b≥ϕ(p)](modp)
我们直接暴力 dfs 遍历每个数求值,由于每个 ppp 最多递归 logp\log plogp 层,因此不会超时。
但是,如何判断 [b≥ϕ(p)][b \ge \phi(p)][b≥ϕ(p)]?其实不难,跑快速幂时判断一下即可。
然后考虑边界情况:
- p=1p=1p=1 时,答案一定为 000
- al=1a_l=1al=1 时,答案一定为 111
aaa 用树状数组维护,再筛一下 ϕ(p)\phi(p)ϕ(p) 即可。
Code
3.58KB,3.1s,95.71MB (in total, C++ 20 with O2) 3.58\text{KB},3.1\text{s},95.71\text{MB}\;\texttt{(in total, C++ 20 with O2) }3.58KB,3.1s,95.71MB(in total, C++ 20 with O2)
// Problem: P3934 [Ynoi2016] 炸脖龙 I
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3934
// Memory Limit: 512 MB
// Time Limit: 2500 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
int lowbit(int x){
return x & -x;
}
template<class T>
struct fenwick{
int n;
vector<T> c;
fenwick() {}
fenwick(int _n): n(_n){
c.resize(n + 1);
}
fenwick(const vector<T> &a): n(a.size()){
c.resize(n + 1);
for(int i = 1; i <= n; i++){
c[i] = c[i] + a[i - 1];
int j = i + lowbit(i);
if(j <= n) c[j] = c[j] + c[i];
}
}
void add(int x, const T& v){
for(int i = x + 1; i <= n; i += lowbit(i)) c[i] = c[i] + v;
}
T ask(int x){
T ans{};
for(int i = x + 1; i; i -= lowbit(i)) ans = ans + c[i];
return ans;
}
T ask(int l, int r){
return ask(r) - ask(l - 1);
}
};
using Node = pair<i64, bool>;
Node power(i64 a, i64 b, i64 p) {
Node res(1, false);
i64 t = a % p;
if (a >= p) {
res.second = true;
res.first %= p;
}
while (b) {
if (b & 1) {
res.first *= t;
}
if (res.first >= p) {
res.second = true;
res.first %= p;
}
t *= t;
if ((b / 2) && t >= p) {
res.second = true;
t %= p;
}
b >>= 1;
}
return res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m;
scanf("%d %d", &n, &m);
vector<i64> a(n);
fenwick<i64> bit(n);
for (int i = 0; i < n; i++) {
scanf("%lld", &a[i]);
bit.add(i, a[i] - (i > 0 ? a[i - 1] : 0LL));
}
vector<bool> np;
vector<int> pri, phi;
auto sieve = [&](int n) {
np.resize(n + 1, false);
phi.resize(n + 1, 0);
phi[1] = 1;
for (int i = 2; i <= n; i++) {
if (!np[i]) {
pri.push_back(i);
phi[i] = i - 1;
}
for (int j = 0; j < pri.size() && 1LL * i * pri[j] <= n; j++) {
np[i * pri[j]] = true;
if (i % pri[j] == 0) {
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
phi[i * pri[j]] = phi[i] * (pri[j] - 1);
}
}
};
sieve(2e7);
auto solve = [&](auto &&self, int l, int r, i64 p) -> Node {
i64 t = bit.ask(l);
if (p == 1) {
return Node(0, true);
}
if (l == r) {
return Node(t % p, t >= p);
}
if (t == 1) {
return Node(1, false);
}
Node mid = self(self, l + 1, r, phi[p]);
if (mid.second) {
mid.first += phi[p];
}
return power(t, mid.first, p);
};
for (int i = 0; i < m; i++) {
int op, l, r;
i64 p;
scanf("%d %d %d %lld", &op, &l, &r, &p);
l--, r--;
if (op == 1) {
bit.add(l, p);
bit.add(r + 1, -p);
}
else {
i64 res = solve(solve, l, r, p).first;
printf("%lld\n", (res % p + p) % p);
}
}
return 0;
}
172万+

被折叠的 条评论
为什么被折叠?



