Loading

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;
}
posted @ 2026-03-29 20:55  Trent900  阅读(16)  评论(0)    收藏  举报