Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
For a fixed query 2 k, stop thinking about the operation one step at a time. Repeatedly adding modulo lets an element move exactly inside one residue class modulo .
So if , position can become any number in congruent to . The exact value of barely matters. Sneaky, but legal.
Let . Every chosen value looks like , where . Think of as the block/level of the number.
For adjacent residues, if then the level does not need to increase. If , the next level must increase by at least .
Therefore query 2 k is YES iff the number of adjacent drops in is less than . Maintain that drop count for every divisor of ; a point update only affects pairs touching the changed index.
For query 2 k, one operation adds modulo to one element. Applying it many times to the same element gives
The set of values reachable from is exactly all values with the same remainder modulo
So the query is equivalent to this cleaner problem:
Can we choose values such that
and
That is the main simplification. The operation itself is just noise after you notice the gcd.
Residues and levels
Fix some divisor of . Define
Every possible final value for position has the form
where
Call the level. There are exactly levels.
Now compare two adjacent positions. We need
There are only two cases:
So every adjacent drop in the residue sequence forces the level to increase by one.
Let
Starting from level , after all forced jumps we need final level at least . Since the maximum allowed level is , sorting is possible exactly when
Equivalently:
Why this is sufficient
Use the greedy construction:
This creates a nondecreasing sequence, because it does the minimum level increase needed at every adjacent pair. If the total number of drops is less than , every chosen value stays below . Done.
No DP. No sorting simulation. Just count the wraps. Very rude of the problem statement to hide that, honestly.
Updates
For every divisor of , maintain
For an update 1 i x, only two adjacent comparisons can change:
So for every divisor :
For query 2 k:
YES iff bad[g] < m / g.Since is always a divisor of , we only store counters for divisors of .
Complexity
Let be the number of divisors of .
For each test case:
2 query costs , basically tiny.The total and are at most , and , so this easily fits.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, m, q;
cin >> n >> m >> q;
vector<int> a(n);
for (int &x : a) cin >> x;
vector<int> divisors;
for (int d = 1; 1LL * d * d <= m; d++) {
if (m % d == 0) {
divisors.push_back(d);
if (d * d != m) divisors.push_back(m / d);
}
}
sort(divisors.begin(), divisors.end());
int D = (int)divisors.size();
vector<int> bad(D, 0);
auto is_bad = [&](int pos, int g) -> int {
return (a[pos] % g) > (a[pos + 1] % g);
};
for (int idx = 0; idx < D; idx++) {
int g = divisors[idx];
for (int i = 0; i + 1 < n; i++) {
bad[idx] += is_bad(i, g);
}
}
auto remove_pair = [&](int pos) {
if (pos < 0 || pos + 1 >= n) return;
for (int idx = 0; idx < D; idx++) {
bad[idx] -= is_bad(pos, divisors[idx]);
}
};
auto add_pair = [&](int pos) {
if (pos < 0 || pos + 1 >= n) return;
for (int idx = 0; idx < D; idx++) {
bad[idx] += is_bad(pos, divisors[idx]);
}
};
while (q--) {
int type;
cin >> type;
if (type == 1) {
int i, x;
cin >> i >> x;
--i;
remove_pair(i - 1);
remove_pair(i);
a[i] = x;
add_pair(i - 1);
add_pair(i);
} else {
int k;
cin >> k;
int g = gcd(k, m);
int idx = (int)(lower_bound(divisors.begin(), divisors.end(), g) - divisors.begin());
cout << (bad[idx] < m / g ? "YES\n" : "NO\n");
}
}
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, m, q;
cin >> n >> m >> q;
vector<int> a(n);
for (int &x : a) cin >> x;
vector<int> divisors;
for (int d = 1; 1LL * d * d <= m; d++) {
if (m % d == 0) {
divisors.push_back(d);
if (d * d != m) divisors.push_back(m / d);
}
}
sort(divisors.begin(), divisors.end());
int D = (int)divisors.size();
vector<int> bad(D, 0);
auto is_bad = [&](int pos, int g) -> int {
return (a[pos] % g) > (a[pos + 1] % g);
};
for (int idx = 0; idx < D; idx++) {
int g = divisors[idx];
for (int i = 0; i + 1 < n; i++) {
bad[idx] += is_bad(i, g);
}
}
auto remove_pair = [&](int pos) {
if (pos < 0 || pos + 1 >= n) return;
for (int idx = 0; idx < D; idx++) {
bad[idx] -= is_bad(pos, divisors[idx]);
}
};
auto add_pair = [&](int pos) {
if (pos < 0 || pos + 1 >= n) return;
for (int idx = 0; idx < D; idx++) {
bad[idx] += is_bad(pos, divisors[idx]);
}
};
while (q--) {
int type;
cin >> type;
if (type == 1) {
int i, x;
cin >> i >> x;
--i;
remove_pair(i - 1);
remove_pair(i);
a[i] = x;
add_pair(i - 1);
add_pair(i);
} else {
int k;
cin >> k;
int g = gcd(k, m);
int idx = (int)(lower_bound(divisors.begin(), divisors.end(), g) - divisors.begin());
cout << (bad[idx] < m / g ? "YES\n" : "NO\n");
}
}
}
return 0;
}