Codeforces Round 1034 (Div. 3) 解题报告
哇太燃了太燃了。
E
就是你推一下式子,你会发现某一个数可以成为 \(mex\) 的 \(k\) 的取值一定是一段区间,差分一下就可以了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 7;
int n, a[N], cnt[N], b[N], ini;
void solve(){
cin >> n;
ini = 0;
for(int i = 0; i <= n; i ++)
cnt[i] = b[i] = 0;
for(int i = 1; i <= n; i ++)
cin >> a[i], b[a[i]] ++;
while(ini <= n && b[ini]) ini ++;
for(int i = 0; i <= ini; i ++){
int l = b[i], r = n - i;
if(l <= r) cnt[l] ++, cnt[r + 1] --;
}
for(int i = 0; i <= n; i ++){
if(i) cnt[i] += cnt[i - 1];
cout << cnt[i] << " ";
}
cout << "\n";
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0);
int t; cin >> t;
while(t --) solve();
return 0;
}
F
把 \(n\) 内所有的质数找出来,然后从大到小,每一次把质数 \(p\) 以及 \(p\) 的倍数中没有被分组的分到一组,然后对每一组进行一次循环移位,那么如果这一组至少有 \(2\) 个元素,就可以保证这一组不会产生任何固定点。那么如果是这样分组的话,对于每一个 \(2p \le n\) 的质数 \(p\),\(p\) 和 \(2p\) 一定会被分到同一组(因为届时 \(2\) 还没有被遍历到,所以 \(2p\) 一定没有被分过)。然后产生固定点的组只有那些 \(2p > n\) 的质数,然后这肯定是最少固定点的方式了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 7;
bool np[N], vis[N];
vector<int> p;
void pre(const int n = 1e5){
np[0] = np[1] = true;
for(int i = 2; i <= n; i ++){
if(!np[i]) p.push_back(i);
for(int j = 0; j < p.size() && i * p[j] <= n; j ++){
np[i * p[j]] = true;
if(i % p[j] == 0) break;
}
}
reverse(p.begin(), p.end());
}
int n, a[N];
void solve(){
cin >> n;
for(int i = 1; i <= n; i ++) vis[i] = false;
for(int x: p){
if(x > n) continue;
vector<int> tmp;
for(int i = x; i <= n; i += x)
if(!vis[i]) tmp.push_back(i);
int s = tmp.back();
for(int i = tmp.size() - 1; i; i --) tmp[i] = tmp[i - 1];
tmp[0] = s;
int idx = 0;
for(int i = x; i <= n; i += x)
if(!vis[i]) vis[i] = true, a[i] = tmp[idx ++];
}
a[1] = 1;
for(int i = 1; i <= n; i ++) cout << a[i] << " ";
cout << "\n";
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0);
pre(); int t; cin >> t;
while(t --) solve();
return 0;
}
G
这个题好燃。考虑到询问时,每一个 \(a_i\) 只能取到在 \(m\) 之内,且与 \(a_i\) 原来的值模 \(\gcd(m,k)\) 同余的所有数。然后我们只需要考虑会出现多少个周期即可。令 \(b_i=a_i \mod gcd(m,k)\),然后 \(cnt\) 代表 \(b\) 中出现相邻逆序对的个数,那么 \(a_i\) 操作后最后一个值最小是 \(cnt \times \gcd(k,m) + b_n\),这个数小于 \(m\) 就是可行的。
维护也很简单,注意到 \(\gcd(k,m)\) 的个数 \(\le\) \(m\) 的因子个数,然后 \(1\) 到 \(5 \cdot 10^5\) 中因子最多的数,因子不超过 \(200\) 个,对于每一个因子单独维护 \(cnt\) 就行了。
//WAR NEVER CHANGES
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 7, M = 207;
int n, r, q, a[M][N], fac[M], m, cnt[M];
void solve(){
cin >> n >> r >> q;
m = 0;
for(int i = 1; i * i <= r; i ++){
if(r % i == 0){
fac[++ m] = i;
if(i * i != r) fac[++ m] = r / i;
}
}
for(int i = 1; i <= n; i ++){
int A; cin >> A;
for(int j = 1; j <= m; j ++) a[j][i] = A % fac[j];
}
for(int j = 1; j <= m; j ++){
cnt[j] = 0;
for(int i = 1; i < n; i ++) if(a[j][i + 1] < a[j][i]) cnt[j] ++;
}
while(q --){
int opt; cin >> opt;
if(opt == 1){
int x, k; cin >> x >> k;
for(int j = 1; j <= m; j ++){
int pre = (x > 1 && a[j][x] < a[j][x - 1]);
int suf = (x < n && a[j][x] > a[j][x + 1]);
a[j][x] = k % fac[j], cnt[j] -= (pre + suf);
pre = (x > 1 && a[j][x] < a[j][x - 1]);
suf = (x < n && a[j][x] > a[j][x + 1]);
cnt[j] += (pre + suf);
}
}
else{
int k; cin >> k;
int g = gcd(k, r);
for(int j = 1; j <= m; j ++){
if(fac[j] != g) continue;
int mx = cnt[j] * g + a[j][n];
cout << (mx < r ? "yes\n" : "no\n");
break;
}
}
}
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0);
int t; cin >> t;
while(t --) solve();
return 0;
}

浙公网安备 33010602011771号