Codeforces Round 902 Div. 2 - A B C(规律) D(思维暴力) E(toposort)

传送门

A. Goals of Victory

对给定 n - 1 组队伍的净得分求和取负即为最后一组队伍的净得分

B. Helmets in Night Light

赛时想法假了,赛后更正
对所有人按照传递花费升序排序,从小到大逐步选取
先花费 p 为传递花费最小的居民分享消息,再一次遍历后面的居民
如果当前居民的传递花费 b 小于等于 p,则当前居民必选,统计其能分享消息给几个居民和花费,且由于 a > 1,故当前居民的被传递花费已经由前面计算过,而不是说将之前的花费花在后面的居民上
如果当前居民的传递花费大于 p,则应该直接传递花费 p 划算

详见代码
Qiansui_code

C. Joyboard

不限制 m 的范围,看所有的数字会出现多少种类

1 2 3 4 ... n - 1 n n + 1
0 0 0 0 ... 0 0 0
0 1 1 1 ... 1 1 1
0 0 2 2 ... 2 2 2
0 0 0 3 ... 3 3 3
\(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\)
0 0 0 0 ... 0 n - 1 n - 1
0 0 0 0 ... 0 0 n
0 1 1 1 ... 1 1 n + 1
0 0 2 2 ... 2 2 n + 2
\(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\)
0 0 0 0 ... 0 0 2n
0 1 1 1 ... 1 1 2n + 1
0 0 2 2 ... 2 2 2n + 2
\(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\)

所以,可得:
\(k = 1, a_{n + 1} = 0\)
\(k = 2, a_{n + 1} \in [1, n - 1] \cap\{ t | t = an, a \in N^+ \} 且 n > 1\)
\(k = 3, a_{n + 1} \in [bn + 1, (b + 1)n - 1],b \in N^+ 且 n > 2\)
$k > 3 $ 无解

D. Effects of Anti Pimples

注意题目的绿色涂的是下标的倍数
先预处理出每个下标被选中涂黑时其下标倍数中的最大值,再对这些最大值排序,从小到大依次选择当前下标 i 和前面 i - 1 个下标构成的集合的任意子集(子集个数为 \(2^{i - 1}\) 个),此时该集合中的最大值即为下标 i 代表的数

void solve(){
	int n;
	cin >> n;
	vector<int> a(n + 1), mx(n + 1, 0);
	for(int i = 1; i <= n; ++ i){
		cin >> a[i];
	}
	for(int i = 1; i <= n; ++ i){
		for(int j = i; j <= n; j += i){
			mx[i] = max(mx[i], a[j]);
		}
	}
	ll ans = 0, base = 1;
	sort(mx.begin() + 1, mx.begin() + 1 + n);
	for(int i = 1; i <= n; ++ i){
		ans = (ans + base * mx[i] % mod) % mod;
		base = base * 2 % mod;
	}
	cout << ans << '\n';
	return ;
}

E. Autosynthesis

参考题解

如果第 i 个下标没有被圈,那么下标 a[i] 必定被圈
如果第 i 个下标被圈了,那么下标 a[i] 可能被圈

那么我们对于每一个 i 向 a[i] 建边,表示不圈与必圈的关系,一共会有 n 个顶点,n 条边,且每个顶点最多在一个环中
如果说图中存在入度为 0 的节点 i,那么节点 i 必须不圈,那么节点 a[i] 必须被圈,那么节点 a[[i]] 的入度也需要 -1,若其入度为 0 则其成为新的入度为 0 的节点
故可以利用 toposort 来处理哪些节点必须被保留

经过这样的操作之后图中剩下的就是环了,对于环,我们可以随意找环上任意一点进行上述操作,同时标记其圈或不圈的状态,如果说存在一个节点又要圈又要不圈,那么该情况就无法满足,输出 -1,否则处理完所有的环即可
此操作等价于对于一个环,如果环的节点个数为奇数,那么必定无法实现;如果环的结点个数为偶数,那么隔一个节点取一个节点即可

详见代码

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long

using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f, mod = 998244353;
int n, ru[maxm], vis[maxm], a[maxm];

queue<int> q;
bool f = true;
void calc(){
	while(q.size()){
		int t = q.front(); q.pop();
		if(vis[t] == -1 || vis[a[t]] == 1){
			f = false; break;
		}
		vis[t] = 1;
		if(vis[a[t]] == -1) continue;
		vis[a[t]] = -1;
		-- ru[a[a[t]]];
		if(ru[a[a[t]]] == 0) q.push(a[a[t]]);
	}
	return ;
}

void solve(){
	cin >> n;
	for(int i = 1; i <= n; ++ i){
		cin >> a[i];
		++ ru[a[i]];
	}
	while(f){
		for(int i = 1; i <= n; ++ i)
			if(ru[i] == 0 && vis[i] == 0) q.push(i);
		if(q.size() == 0){
			for(int i = 1; i <= n; ++ i){
				if(vis[i] == 0){
					q.push(i); calc();
				}
			}
			break;
		}else calc();
	}
	if(f){
		vector<int> ans;
		for(int i = 1; i <= n; ++ i)
			if(vis[i] == 1) ans.push_back(a[i]);
		cout << ans.size() << '\n';
		for(auto x : ans) cout << x << ' ';
	}else cout << -1 << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}
posted @ 2023-10-08 21:02  Qiansui  阅读(333)  评论(0)    收藏  举报