CF1783

Make it Beautiful

构造题。

如果元素互不相同,我们可以降序排列。

如果有相同元素的话,就多构造几个降序排列拼在一起,可以证明符合条件。

复杂度 O(n)

Matrix of Differences

还是构造题。

我们思考是否对于任意一个 n 都可以构造出一个矩形使得相邻之差包含 1n21

然后发现可以。

先构造出一个这样的序列:1,n2,2,n21,3,n22......

然后 S 型将其放入 n×n 的矩形即可。

复杂度 O(n2)

Yet Another Tournament

贪心。

我最初步的想法是将 a 从大到小排序,然后尽可能多选。

但是我们发现其他球队胜的次数会根据我们选的方法而改变,所以这是不行的。

假设最多能胜 k 场,那么容易发现可能会影响最终排名的只有球队 k+1 和球队 k+2

于是我们必选 k+1,贪一下,必选 k+2,贪一下,必选 a 值最小的,贪一下。

三种情况取最优排名即可。

复杂度 O(nlogn)

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
int T, n, m, b[N], c[N], vis[N];
struct node{
	int a, id;
}x[N];
bool cmp(node xx, node yy) {
	return xx.a < yy.a;
}
int getpai(int cnt) {
	for (int i = 1; i <= n; ++i) c[i] = i - 1 + (vis[i] == 0);
	int pai = 0;
	for (int i = 1; i <= n; ++i) {
		if (c[i] > cnt) {
			++pai;
		}
	}
	return pai + 1;
}
int solve(int w) {
	if (w > n || m < b[w]) return INT_MAX;
	for (int i = 1; i <= n; ++i) vis[i] = 0;
	int t = m - b[w], cnt = 1;
	vis[w] = 1;
	for (int i = 1; i <= n; ++i) {
		if (x[i].id == w) continue;
		if (x[i].a <= t) {
			t -= x[i].a;
			++cnt;
			vis[x[i].id] = 1;
		}
	}
	return getpai(cnt);
}
int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> T;
	while (T--) {
		cin >> n >> m;
		for (int i = 1; i <= n; ++i) {
			cin >> x[i].a;
			b[i] = x[i].a;
			x[i].id = i;
			vis[i] = 0;
		}
		sort(x + 1, x + n + 1, cmp);
		int cnt = 0, t = m;
		for (int i = 1; i <= n; ++i) {
			if (t >= x[i].a) {
				t -= x[i].a;
				++cnt;
				vis[x[i].id] = 1;
			}
		}
		int ans = getpai(cnt);
		ans = min(ans, min(solve(cnt + 1), solve(cnt + 2)));
		cout << ans << endl;
	}
	return 0;
}

Different Arrays

怪怪的 DP。

定义 fi,j 为已经处理完前 i1 项,现在考虑第 i 项,且 ai+1=j 的情况下最终能生成的序列的个数。

容易发现,当 j=0 时序列不会发生变化,而 j0 时有产生两种情况。

所以转移方程为:

fi,j={fi+1,ai+2j=0fi+1,ai+2j+fi+1,ai+2+jelse

边界为 fn1,j=1

注意,第二维 j 的范围是 [na,+na],所以要加上一个数平移一下。

复杂度 O(n3)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 300 + 5, nn = 300 * 300, mod = 998244353;
int n, a[N];
ll f[N][N * N * 2];
ll dfs(int i, int j) {
	if (i == n - 1) return f[i][j + nn] = 1;
	if (f[i][j + nn] != -1) return f[i][j + nn];
	if (j) f[i][j + nn] = (dfs(i + 1, a[i + 2] - j) + dfs(i + 1, a[i + 2] + j)) % mod;
	else f[i][j + nn] = dfs(i + 1, a[i + 2]);
	return f[i][j + nn];
}
int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; ++i) cin >> a[i];
	memset(f, -1, sizeof(f));
	cout << dfs(1, a[2]) << endl;
	return 0;
}

Game of the Year

第一次读错题了,以为尝试数不清空......

如果 aibi,不用管。

如果 ai>bi,考虑什么情况下 aik>bik

然后我们发现如果 k[bi,ai) 中有倍数,那么 k 不能选。

于是可以将所有的 [bi,ai) 标记一下,差分 O(1) 解决,然后直接枚举每一个 k 看是否可行即可。

复杂度调和级数 O(nlogn)

#include <bits/stdc++.h>
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
const int N = 1e6 + 5;
int T, n, a[N], b[N], vis[N];
vector<int> ans;
int main() {
	cin >> T;
	while (T--) {
		n = read();
		ans.clear();
		for (int i = 1; i <= n; ++i) a[i] = read(), vis[i] = 0;
		for (int i = 1; i <= n; ++i) b[i] = read();
		for (int i = 1; i <= n; ++i) {
			if (a[i] > b[i]) {
				++vis[b[i]];
				--vis[a[i]];
			}
		}
		for (int i = 1; i <= n; ++i) vis[i] += vis[i - 1];
		for (int x = 1; x <= n; ++x) {
			bool flag = 1;
			for (int i = x; i <= n; i += x) {
				if (vis[i]) flag = 0;
			}
			if (flag) ans.push_back(x);
		}
		cout << ans.size() << endl;
		for (int i = 0; i < ans.size(); ++i) printf("%d ", ans[i]);
		cout << endl;
	}
	return 0;
}

Double Sort II

不会,看了眼题解,明白了一个小 trick。

我们可以把序列上的元素交换变为图的形式。

考虑只有一个序列的情况。

我们可以在 iai 之间连一条边,最小交换次数为总点数减去环的个数。

原因很显然,对于一个环,我们交换完其中 x1 个元素后,最后一个元素肯定在它该在的位置。

如果有两个序列呢?

我们可以“固定”一些数,也就是上述的环中最后一个元素。

如果我们固定 u,那么 u 在两张图中的环中的元素就不能再选了。

然后发现这就是一个裸的二分图最大匹配问题。

建图直接跑 dinic 就行了。

注意,由于序列中每个元素只会有一条入边和一条出边,所以构成的图一定是若干个简单环,这样就可以直接用并查集找了。

复杂度 O(n2)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5, inf = INT_MAX >> 2;
int n, a[N], b[N], id[N], id2[N], cnt = 0, fa[N], s, t, head[N], nex[N], to[N], val[N], dep[N], cur[N], fm[N], no[N], tot = 1;
int ff(int x) {return fa[x] == x?x:fa[x] = ff(fa[x]);}
void add(int u, int v) {
	val[++tot] = 1;
	to[tot] = v;
	nex[tot] = head[u];
	head[u] = tot;
	val[++tot] = 0;
	to[tot] = u;
	nex[tot] = head[v];
	head[v] = tot;
}
queue<int> q;
int bfs() {
	for (int i = 1; i <= t; ++i) dep[i] = 0, cur[i] = head[i];
	dep[s] = 1; q.push(s);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for (int i = head[u]; i; i = nex[i]) {
			int v = to[i];
			if (val[i] && !dep[v]) {
				dep[v] = dep[u] + 1;
				q.push(v);
			}
		}
	}
	return dep[t];
}
int dfs(int u, int c) {
	if (u == t) return c;
	int out = 0;
	for (int i = cur[u]; i && c; i = nex[i]) {
		cur[u] = i;
		int v = to[i];
		if (val[i] && dep[v] == dep[u] + 1) {
			int tmp = dfs(v, min(c, val[i])); 
			val[i] -= tmp; val[i ^ 1] += tmp; out += tmp; c -= tmp;
		}
	}
	if (!out) dep[u] = 0;
	return out;
}
int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> n;
	s = 2 * n + 1; t = s + 1;
	for (int i = 1; i <= n; ++i) cin >> a[i], fa[i] = i;
	for (int i = 1; i <= n; ++i) cin >> b[i];
	for (int i = 1; i <= n; ++i) fa[ff(i)] = ff(a[i]);
	int num = 0;
	for (int i = 1; i <= n; ++i) {
		if (i == ff(i)) {
			id[i] = ++num;
			add(s, num);
		}
	}
	for (int i = 1; i <= n; ++i)  id[i] = id[ff(i)];
	for (int i = 1; i <= n; ++i) fa[i] = i;
	for (int i = 1; i <= n; ++i) fa[ff(i)] = ff(b[i]);
	for (int i = 1; i <= n; ++i) {
		if (i == ff(i)) {
			id2[i] = ++num;
			add(num, t);
		}
	}
	for (int i = 1; i <= n; ++i) id2[i] = id2[ff(i)];
	for (int i = 1; i <= n; ++i) {
		add(id[i], id2[i]);
		fm[i] = tot - 1;
	}
	int ans = n;
	while (bfs()) ans -= dfs(s, inf);
	cout << ans << endl;
	for (int i = 1; i <= n; ++i) {
		if (!val[fm[i]]) {
			no[i] = 1;
		}
	}
	for (int i = 1; i <= n; ++i) {
		if (!no[i]) {
			cout << i << " ";
		}
	}
	cout << endl;
	return 0;
}

本文作者:HQJ2007

本文链接:https://www.cnblogs.com/HQJ2007/p/17561581.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   HQJ2007  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起