Codeforces Round #565 (Div. 3)

http://codeforces.com/contest/1176

A B C D E F
1A 1A 1A after the game by tutorial after the game by myself after the game by myself

\(rank:1097\) (赛中有点事,精神恍惚去了233)

A

由题可知,分别消掉\(1\)\(2,3,5\)分别需要\(1,2,3\)的花费,于是我们算出\(n\)中包含的\(2,3,5\)的个数就好

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
typedef long long ll;
int q;
ll m;
int main() {
	cin >> q;
	while (q--) {
		cin >> m;
		int a = 0, b = 0, c = 0;
		while (m % 2 == 0) {
			a++; m /= 2;
		}
		while (m % 3 == 0) {
			b++; m /= 3;
		}
		while (m % 5 == 0) {
			c++; m /= 5;
		}
		if (m == 1)cout << a + b * 2 + c * 3 << '\n';
		else cout << "-1\n";
	}
	return 0;
}

B

\(a_i\)\(3\)取模,记\(cnt[x]=x\)的数量,则\(ans\)=\(cnt[0] + min(cnt[1],cnt[2]) + \lfloor \frac{max(cnt[1],cnt[2])-min(cnt[1],cnt[2])}{3}\rfloor\)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
typedef long long ll;
int t, n, a, cnt[3];

int main() {
	cin >> t;
	while (t--) {
		cin >> n;
		for (int i = 0; i < 3; i++)cnt[i] = 0;
		for (int i = 1; i <= n; i++) {
			cin >> a;
			cnt[a % 3]++;
		}
		if (cnt[1] > cnt[2])swap(cnt[1], cnt[2]); cnt[2] -= cnt[1];
		int ans = cnt[0] + cnt[1] + cnt[2] / 3;
		cout << ans << '\n';
	}
	return 0;
}

C

记原序列中 \(subsequences\) \(4,8,15,16,23,42\)的数量为\(m\),则答案为$$n-6*m$$

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
typedef long long ll;
int n, a;
int mp[100], cnt[7];
int main() {
	mp[4] = 1; mp[8] = 2; mp[15] = 3; mp[16] = 4; mp[23] = 5; mp[42] = 6;
	cin >> n;
	cnt[0] = 5e5 + 5;
	for (int i = 1; i <= n; i++) {
		cin >> a;
		a = mp[a];
		if (cnt[a - 1]) {
			cnt[a - 1]--; cnt[a]++;
		}
	}
	cout << n - cnt[6] * 6 << '\n';
	return 0;
}

D

一个很明显的想法即是从大到小贪心,因为当前最大的一个一定要和前面的某个进行配对。
记当前数为\(x\)\(mp[x]\)= \(\{k:The\ k^{th}\ prime\ is\ x\}\),\(low[x] = x\)的最小素因子
如果\(x\)为素数,则把\(mp[x]\)加入答案。
否则,把\(x\)加入答案。
具体实现用一个\(multiset\)每次从最大的,然后删除当前以及匹配的那个。\(mp\)\(low\)都可以通过线筛\(O(n)\)搞定

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2750131 + 5, BOUND = 2750131;
typedef long long ll;
int n, x, primes[MAXN], cnt, low[MAXN], mp[MAXN];
bool is_prime[MAXN];
vector<int> ans;
multiset<int> st;
void init() {
	is_prime[1] = 1;
	for (int i = 2; i <= BOUND; i++) {
		if (!is_prime[i])primes[++cnt] = i;
		for (int j = 1; j <= cnt && primes[j] * i <= BOUND; j++) {
			is_prime[i*primes[j]] = 1; low[i*primes[j]] = primes[j];
			if (i%primes[j] == 0) {
				break;
			}
		}
	}
	for (int i = 1; i <= cnt; i++) {
		mp[primes[i]] = i;
	}
}
int main() {
	init();
	cin >> n;
	for (int i = 1; i <= n * 2; i++) {
		cin >> x;
		st.insert(x);
	}
	while (st.size()) {
		int x = *st.rbegin();
		st.erase(--st.end());
		if (is_prime[x]) {
			auto it = st.find(x / low[x]);
			ans.push_back(x); st.erase(it);
		}
		else {
			int t = mp[x];
			auto it = st.find(t);
			ans.push_back(t); st.erase(it);
		}
	}
	for (int i = 0; i < ans.size(); i++) {
		cout << ans[i] << " \n"[i == ans.size() - 1];
	}
	return 0;
}

E

最多选\(\lfloor \frac{n}{2} \rfloor\)个,所以我们直接遍历一遍图,对图进行黑白染色,然后输出颜色比较少的点就好,可以证明这样一定点数少于等于\(\lfloor \frac{n}{2} \rfloor\),并且满足题设条件

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
int t, n, m, u, v;
bool vis[MAXN];
vector<int > ans, G[MAXN];
void dfs(int u, int f, int d) {
	vis[u] = 1;
	if (d == 1)ans.push_back(u);
	for (int v : G[u]) {
		if (vis[v])continue;
		dfs(v, u, d ^ 1);
	}
}
int main() {
	cin >> t;
	while (t--) {
		cin >> n >> m;
		for (int i = 1; i <= n; i++)G[i].clear();
		ans.clear();
		for (int i = 1; i <= m; i++) {
			cin >> u >> v;
			G[u].push_back(v); G[v].push_back(u);
		}
		for (int i = 1; i <= n; i++)vis[i] = 0;
		dfs(1, 0, 0);
		if (ans.size() <= n / 2) {
			cout << ans.size() << '\n';
			for (int i = 0; i < ans.size(); i++) {
				cout << ans[i] << " \n"[i == ans.size() - 1];
			}
		}
		else {
			for (int i = 1; i <= n; i++)vis[i] = 0;
			ans.clear();
			dfs(1, 0, 1);
			cout << ans.size() << '\n';
			for (int i = 0; i < ans.size(); i++) {
				cout << ans[i] << " \n"[i == ans.size() - 1];
			}
		}
	}
	return 0;
}

F

简单\(dp\)。定义\(dp[i][x]\)\(i\)为当前的\(turn\)\(x\)为当前选了多少张牌,由题,我们只关心 \(x\bmod10\)的值,以此来判断什么是否\(double\ damage\),然后转移就好。细节处理看代码。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5, BOUND = 2750131;
typedef long long ll;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
int n, x, c, d, mx[4], v[MAXN][6];
ll dp[MAXN][12];
priority_queue<int, vector<int>, greater<int>> s;
inline int calc(int j, int k) {
	return j - k < 0;
}
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> x;
		memset(mx, 0, sizeof(mx));
		for (int j = 1; j <= x; j++) {
			cin >> c >> d;
			if (c == 1) {
				s.push(d);
				if (s.size() > 3)s.pop();
			}
			else {
				mx[c] = max(mx[c], d);
			}
		}
		int y = 3 - s.size() + 1;
		while (s.size()) {
			v[i][y++] = s.top(); s.pop();
		}
		v[i][4] = mx[2]; v[i][5] = mx[3];
	}
	for (int i = 0; i < 10; i++)dp[0][i] = -INFL;
	dp[0][0] = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j < 10; j++) {
			dp[i][j] = dp[i - 1][j];
			if (v[i][5])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 1 + 10) % 10] + v[i][5] * calc(j, 1) + v[i][5]);
			if (v[i][4])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 1 + 10) % 10] + v[i][4] * calc(j, 1) + v[i][4]);
			if (v[i][3])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 1 + 10) % 10] + v[i][3] * calc(j, 1) + v[i][3]);
			if (v[i][4] && v[i][3])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 2 + 10) % 10] + v[i][4] + v[i][3] + max(v[i][4], v[i][3])*calc(j, 2));
			if (v[i][3] && v[i][2])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 2 + 10) % 10] + v[i][2] + v[i][3] + max(v[i][2], v[i][3])*calc(j, 2));
			if (v[i][3] && v[i][2] && v[i][1])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 3 + 10) % 10] + v[i][3] + v[i][2] + v[i][1] + max(v[i][1], max(v[i][2], v[i][3]))*calc(j, 3));
		}
	}
	ll ans = 0;
	for (int i = 0; i < 10; i++)ans = max(ans, dp[n][i]);
	cout << ans << '\n';
	return 0;
}
posted @ 2019-06-11 13:10  sienna  阅读(187)  评论(0编辑  收藏  举报