P3747 [六省联考 2017] 相逢是问候
[六省联考 2017] 相逢是问候
题目描述
Informatik verbindet dich und mich.
信息将你我连结。
B 君希望以维护一个长度为
一共有
-
0 l r
表示将第 个到第 个数( )中的每一个数 替换为 ,即 的 次方,其中 是输入的一个常数,也就是执行赋值 。 -
1 l r
求第 个到第 个数的和,也就是输出:
因为这个结果可能会很大,所以你只需要输出结果
输入格式
第一行有四个整数
接下来一行
接下来
- 如果是
的话,表示这是一个修改操作,操作的参数为 。 - 如果是
的话,表示这是一个询问操作,操作的参数为 。
输出格式
对于每个询问操作,输出一行,包括一个整数表示答案
样例 #1
样例输入 #1
4 4 7 2
1 2 3 4
0 1 4
1 2 4
0 1 4
1 1 3
样例输出 #1
0
3
样例 #2
样例输入 #2
1 40 19910626 2
0
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
0 1 1
1 1 1
样例输出 #2
1
2
4
16
65536
11418102
18325590
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
13700558
提示
【数据范围】
对于
对于另外
对于另外
对于另外
对于另外
对于另外
对于另外
对于
Solution
首先对于题目中的修改操作,肯定是不能使用常规维护 tag
的方式进行处理的,因此尝试发现一下特殊性质。观察样例二可以发现,在进行了一定次数修改过后,
回来看
考虑将这个结论运用到此题上来,因为证明出来了一个数最多只会变
发现每次进行快速幂的时候的底数都不变,为
代码写分块的话细节很少,注意判断光速幂的过程中是否出现了指数
#include<bits/stdc++.h>
using namespace std;
constexpr int _N = 5e4 + 5, _LEN = 250 + 5, _S = 1e4, _MS = _S + 5;
int n, m, p, c, ori[_N], a[_N], tim[_N];
map<int, int> phi, id;
int len, cnt, bl[_N], pos[_N], br[_N], sum[_N];
bool tag[_N];
int Getphi(int x) {
int res = x;
for (int i = 2; i * i <= x; ++i) {
if (x % i) continue;
res = res / i * (i - 1);
while (!(x % i)) x /= i;
}
if (x > 1) res = res / x * (x - 1);
return res;
}
int pw[_LEN][_MS][2], tP = 0;
bool flag[_LEN][_MS][2];
void Init(int P) {
int x = id[P] = ++tP;
pw[x][0][0] = pw[x][0][1] = 1;
for (int i = 1; i <= _S; ++i) {
flag[x][i][0] = flag[x][i - 1][0] || (1ll * pw[x][i - 1][0] * c >= P);
pw[x][i][0] = 1ll * pw[x][i - 1][0] * c % P;
}
for (int i = 1; i <= _S; ++i) {
flag[x][i][1] = flag[x][i - 1][1] || (1ll * pw[x][i - 1][1] * pw[x][i - 1][_S] >= P);
pw[x][i][1] = 1ll * pw[x][i - 1][1] * pw[x][_S][0] % P;
}
}
inline pair<int, bool> Lpow(int x, int P) {
int i = id[P];
int fir = 1ll * pw[i][x % _S][0] * pw[i][x / _S][1] % P;
int sec = flag[i][x % _S][0] || flag[i][x / _S][1] || (1ll * pw[i][x % _S][0] * pw[i][x / _S][1] >= P);
return {fir, sec};
}
inline pair<int, bool> GetAns(int x, int p, int tim) {
if (!tim) return {x % p, x >= p};
if (p == 1) return {0, 1};
auto tmp = GetAns(x, phi[p], tim - 1);
int b = tmp.first + tmp.second * phi[p];
return Lpow(b, p);
}
void Change(int i) {
(sum[pos[i]] += p - a[i]) %= p, ++tim[i];
a[i] = GetAns(ori[i], p, tim[i]).first;
(sum[pos[i]] += a[i]) %= p;
}
void Modify(int l, int r) {
if (pos[l] == pos[r])
for (int i = l; i <= r; ++i) Change(i);
else {
for (int i = l; i <= br[pos[l]]; ++i) Change(i);
for (int i = pos[l] + 1; i < pos[r]; ++i) {
if (tag[i]) continue; tag[i] = 1;
for (int j = bl[i]; j <= br[i]; ++j) {
int tmp = a[j]; Change(j);
if (a[j] != tmp) tag[i] = 0;
}
}
for (int i = bl[pos[r]]; i <= r; ++i) Change(i);
}
}
int Query(int l, int r) {
int res = 0;
if (pos[l] == pos[r])
for (int i = l; i <= r; ++i) (res += a[i]) %= p;
else {
for (int i = l; i <= br[pos[l]]; ++i) (res += a[i]) %= p;
for (int i = pos[l] + 1; i < pos[r]; ++i) (res += sum[i]) %= p;
for (int i = bl[pos[r]]; i <= r; ++i) (res += a[i]) %= p;
}
return res;
}
signed main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m >> p >> c;
if (n == 1) len = 1;
else len = sqrt(n / log2(n));
cnt = (n - 1) / len + 1;
for (int i = p; i > 1; i = phi[i]) phi[i] = Getphi(i), Init(i);
Init(1);
for (int i = 1; i <= n; ++i) cin >> a[i], ori[i] = a[i];
for (int i = 1; i <= cnt; ++i) {
bl[i] = (i - 1) * len + 1;
br[i] = min(n, i * len);
}
for (int i = 1; i <= cnt; ++i)
for (int j = bl[i]; j <= br[i]; ++j)
pos[j] = i, (sum[i] += a[j]) %= p;
for (int i = 1, opt, l, r; i <= m; ++i) {
cin >> opt >> l >> r;
if (opt) cout << Query(l, r) << '\n';
else Modify(l, r);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步