Codeforces Round 1034 (Div. 3) G题题解记录
大致题意:给定一个正整数mmm,一个数组aaa,可以进行若干次操作:
1:idx,x1:idx,x1:idx,x:令ai:=xa_i:=xai:=x;
2:k2:k2:k:查询:是否能够针对每一个aia_iai都进行如下操作:ai=(ai+xk)%m,x≥0a_i=(a_i+xk)\%m,x\ge0ai=(ai+xk)%m,x≥0,使得得到的新的数组呈现非递减排列(不实际改变,只询问)。
解:
首先,我们需要知道,aia_iai变换的值域。看一下这个式子(ai+xk)%m=ai+xk=ym+r(a_i+xk)\%m=a_i+xk=ym+r(ai+xk)%m=ai+xk=ym+r。而由于xk−ym=zdxk-ym=zdxk−ym=zd,所以r=ai+zd,z≥0r=a_i+zd,z\ge0r=ai+zd,z≥0。而r%d=ai%dr\%d=a_i\%dr%d=ai%d(两边同时%d\%d%d),所以aia_iai所有可以变化的数为一个%d\%d%d意义下的同余类。也就是说,aia_iai可以变化的最小的数就是ai%da_i\%dai%d。
至此可以得出aia_iai经过变化后的值域:{t+zd∣z≥0,t=ai%d,t+zd<m}\{t+zd|z\ge0,t=a_i\%d,t+zd<m\}{t+zd∣z≥0,t=ai%d,t+zd<m},换言之,即为:{t,t+d,t+2d,...,t+nd}(t+nd<m)\{t,t+d,t+2d,...,t+nd\}(t+nd<m){t,t+d,t+2d,...,t+nd}(t+nd<m)。
如何保证非递减呢?我们可以贪心地考虑:aia_iai取≥ai−1\ge a_{i-1}≥ai−1的最小的数。
小于mmm的数中,根据每次+d+d+d可以划分成几类。什么意思?举个例子:d=7,m=21d=7,m=21d=7,m=21。没有跳跃的时候,aia_iai可能等于0,1,2,3,4,5,60,1,2,3,4,5,60,1,2,3,4,5,6;跳跃一次的时候,aia_iai可能等于7,8,9,10,...,137,8,9,10,...,137,8,9,10,...,13。以此类推,根据跳跃次数,在跳跃次数相同的时候,如果ai>ai+1a_i>a_{i+1}ai>ai+1,那么在先前保证贪心策略下,ai+1a_{i+1}ai+1必须进行一次跳跃才能保证≥ai\ge a_i≥ai。我们初始化所有的数都是没有跳跃的情况:ai%=da_i\%=dai%=d。从0次跳跃开始,最多可以跳跃多少次?0+7+7+7=21,1+7+7+7=220+7+7+7=21,1+7+7+7=220+7+7+7=21,1+7+7+7=22。最多可以跳跃m/d−1m/d-1m/d−1次。所以,对于是否可以组成非递减序列,我们只需要判断跳跃次数cntcntcnt和m/d−1m/d-1m/d−1的大小即可。
现在考虑操作111修改:如果aidxa_{idx}aidx变成xxx,其可能会影响的只有左边和右边两个数。所以只需要判断修改前后大小关系,更新cntcntcnt即可。
我们预处理出所有可能作为gcd(k,m)gcd(k,m)gcd(k,m)的值,即mmm的因数。每次查询直接根据cntcntcnt的值与mid/d−1mid/d-1mid/d−1的大小关系来判断,更新的时候更新所有因数。
#include<bits/stdc++.h>#define endl '\n'
#define pii pair<int,int>using namespace std;const int one = 1;
const double eps = 1e-8;
const int inf = 1e18;const int mod = 1e9 + 7;int lowbit(int x) {return x & (-x);
}int qp(int a, int b, int p) {int res = 1;while (b) {if (b & 1) {res = res % p * (a % p) % p;}b >>= 1;a = a % p * (a % p) % p;}return res % p;
}vector<vector<int>> fac;void init(int n) {fac.assign(n + 1, {});for (int i = 1; i <= n; i++) {for (int j = i; j <= n; j += i) {fac[j].push_back(i);}}
}void solve() {int n, q;int m;cin >> n >> m >> q;vector<int> a(n + 1);for (int i = 1; i <= n; i++) cin >> a[i];map<int, int> cnt;for (auto &it: fac[m]) {for (int i = 1; i < n; i++) {if (a[i] % it > a[i + 1] % it) cnt[it]++;}}while (q--) {int op;cin >> op;if (op == 1) {int idx, x;cin >> idx >> x;if (idx > 1) {for (auto &f: fac[m]) {if (a[idx - 1] % f > a[idx] % f) cnt[f]--;if (a[idx - 1] % f > x % f)cnt[f]++;}}if (idx < n) {for (auto &f: fac[m]) {if (a[idx] % f > a[idx + 1] % f) cnt[f]--;if (x % f > a[idx + 1] % f)cnt[f]++;}}a[idx] = x;} else {int t;cin >> t;int d = gcd(t, m);if (cnt[d] <= (m / d - 1)) cout << "YES" << endl;else cout << "NO" << endl;}}}signed main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int T = 1;init(5e5);cin >> T;while (T--) solve();return 0;
}