Codeforces Round #607 (Div. 1) Solution

从这里开始

  我又不太会 div 1 A? 我菜爆了。。。

Problem A Cut and Paste

  暴力模拟一下。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;

const int N = 1e6 + 5;
const int Mod = 1e9 + 7;

int T;
int x;
int len;
char s[N];

int paste(int s1, int t1, int s2) {
	int i = s2;
	for (i = s2; i <= x && i - s2 + s1 <= t1; i++)
		s[i] = s[i - s2 + s1];
	return i;
}

void solve() {
	scanf("%d", &x);
	scanf("%s", s + 1);
	len = strlen(s + 1);
	int rlen = len;
	for (int i = 1; i <= x; i++) {
		int t = s[i] - '0' - 1;
		len = ((i + (len - i) * 1ll * (t + 1)) % Mod + Mod) % Mod;
		int qaq = rlen;
		while (t--)
			rlen = paste(i + 1, qaq, rlen + 1) - 1;
	}
	printf("%d\n", len);
}

int main() {
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

Problem B Beingawesomeism

  不难注意到答案不会超过 4.

  • 答案为 0,这个很 trivial
  • 答案小于等于 1 显然是存在一个边界被完全覆盖
  • 答案小于等于 2,存在一个 A 在角落或者完整的一行或一列为 A
  • 答案小于等于 3,存在 1 个 A 在边界上
  • 剩下的情况答案为 4

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;

const int N = 66;

int T, n, m;
char s[N][N];

int count(int x1, int y1, int x2, int y2) {
	int x = 0;
	for (int i = x1; i <= x2; i++) {
		for (int j = y1; j <= y2; j++) {
			x += s[i][j] == 'A';
		}
	}
	return x;
}

void solve() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%s", s[i] + 1);
	}
	int c = count(1, 1, n, m);
	if (!c) {
		puts("MORTAL");
		return;
	}
	if ((c == n * m)) {
		puts("0");
		return;
	}
	boolean havec = (s[1][1] == 'A' || s[n][1] == 'A' || s[1][m] == 'A' || s[n][m] == 'A');
	int L = count(1, 1, n, 1);
	int R = count(1, m, n, m);
	if (L == n || R == n) {
		puts("1");
		return;
	}
	int U = count(1, 1, 1, m);
	int D = count(n, 1, n, m);
	if (U == m || D == m) {
		puts("1");
		return;
	}
	if (havec) {
		puts("2");
		return;
	}
	for (int i = 1; i <= n; i++) {
		if (count(i, 1, i, m) == m) {
			puts("2");
			return;
		}
	}
	for (int i = 1; i <= m; i++) {
		if (count(1, i, n, i) == n) {
			puts("2");
			return;
		}
	}
	if (L + R + U + D) {
		puts("3");
		return;
	}
	puts("4");
}

int main() {
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

Problem C Jeremy Bearimy

  最大的话,显然以重心为根,答案为每个点的深度和

  最小的话,显然每个点的子树内至多有 1 个未匹配点,dp 即可。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;

const int N = 6e5 + 5;

#define ll long long
#define pii pair<int, int>

const ll llf = (signed ll) (~0ull >> 3);

template <typename T>
boolean vmin(T& a, T b) {
	if (a > b) {
		a = b;
		return true;
	}
	return false;
}

int T;
int n, n2;
int sz[N];
vector<pii> G[N];

int get_sz(int p, int fa) {
	sz[p] = 1;
	for (auto E : G[p]) {
		int e = E.first;
		if (e == fa)
			continue;
		sz[p] += get_sz(e, p);
	}
	return sz[p];
}

int get_g(int p, int fa) {
	for (auto E : G[p]) {
		int e = E.first;
		if (e == fa)
			continue;
		if (sz[e] > n) {
			return get_g(e, p);
		}
	}
	return p;
}

ll dep[N];
void dfs(int p, int fa) {
	for (auto E : G[p]) {
		int e = E.first;
		int w = E.second;
		if (e == fa)
			continue;
		dep[e] = dep[p] + w;
		dfs(e, p);
	}
}

ll f[N][2];
void dp(int p, int fa) {
	static ll g[2];
	f[p][0] = llf, f[p][1] = 0;
	for (auto E : G[p]) {
		int e = E.first;
		int w = E.second;
		if (e == fa)
			continue;
		dp(e, p);
		g[0] = g[1] = llf;
		vmin(g[0], f[p][0] + f[e][0]);
		vmin(g[0], f[p][1] + f[e][1] + w);
		vmin(g[1], f[p][0] + f[e][1] + w);
		vmin(g[1], f[p][1] + f[e][0]);
		f[p][0] = g[0];
		f[p][1] = g[1];
	}
}

void solve() {
	scanf("%d", &n);
	n2 = n << 1;
	for (int i = 1; i <= (n << 1); i++) {
		G[i].clear();
	}
	for (int i = 1, u, v, t; i < n2; i++) {
		scanf("%d%d%d", &u, &v, &t);
		G[u].emplace_back(v, t);
		G[v].emplace_back(u, t);
	}
	get_sz(1, 0);
	int g = get_g(1, 0);
	dep[g] = 0;
	dfs(g, 0);
	ll ansmx = 0;
	for (int i = 1; i <= n2; i++) {
		ansmx += dep[i];
	}
	dp(g, 0);
	printf("%lld %lld\n", f[g][0], ansmx);
}

int main() {
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

Problem D Miss Punyverse

  考虑如果子树内留下的决策不是已有的合法划分最多的一个,至多使答案增加 1,但这里会减少 1,因此子树内决策只用保留合法划分最多,且未结束划分的一块的和最大。

  然后 dp 即可。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;

#define ll long long

#define pii pair<int, ll>

pii operator + (pii a, pii b) {
	return pii(a.first + b.first, a.second + b.second);
}

const int N = 3005;

int T, n, m;
int sz[N];
pii f[N][N];
int a[N], b[N];
vector<int> G[N];

pii work(pii x) {
	x.first += x.second > 0;
	x.second = 0;
	return x;
}

void dfs(int p, int fa) {
	static pii g[N];
	for (int i = 0; i <= m; i++)
		f[p][i] = pii(-N, 0);
	f[p][0] = pii(0, 0);
	sz[p] = 0;
	for (auto e : G[p]) {
		if (e == fa)
			continue;
		dfs(e, p);
		for (int i = 0; i <= sz[p] + sz[e] && i <= m; i++)
			g[i] = pii(-N, 0);
		for (int i = 0; i <= sz[p]; i++) {
			for (int j = 0; j < sz[e] && i + j <= m; j++) {
				g[i + j] = max(g[i + j], f[p][i] + f[e][j]);
				if (j < m)
					g[i + j + 1] = max(g[i + j + 1], f[p][i] + work(f[e][j]));
			}
		}
		for (int i = 0; i <= sz[p] + sz[e] && i <= m; i++)
			f[p][i] = g[i];
		sz[p] += sz[e];
	}
	++sz[p];
	for (int i = 0; i < sz[p]; i++) {
		f[p][i].second += a[p] - b[p];
	}
}

void solve() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", b + i);
	}
	for (int i = 1; i <= n; i++) {
		scanf("%d", a + i);
	}
	for (int i = 1; i <= n; i++)
		G[i].clear();
	for (int i = 1, u, v; i < n; i++) {
		scanf("%d%d", &u, &v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1, 0);
	int ans = work(f[1][m - 1]).first;
	printf("%d\n", ans);
}

int main() {
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

Problem E Kirchhoff's Current Loss

  这个 E 感觉挺简单的,可惜我没时间做了,sad.....

  考虑 $n$ 个电阻串联,答案为 $r$,这个很显然

  考虑 $n$ 个电阻并联,答案为 $n^2r$,证明考虑用均值不等式归纳。

  简单归纳一下可以发现,最终一定是等效于 $k$ 个电阻并联。

  然后 dp 即可。

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;

const int N = 2e5 + 5;

int T;
int n, m, r;
char s[1000000];
boolean ispar[N];
vector<int> G[N];

int newnode() {
	++n;
	G[n].clear();
	ispar[n] = false;
	return n;
}

int id[N];
int build(char* &s) {
	int p = newnode();
	while (true) {
		while (*s == ' ')
			s++;
		if (!*s || *s == ')')
			return p;
		if (*s == 'P') {
			ispar[p] = true;
		} else if (*s == 'S') {
			ispar[p] = false;
		} else if (*s == '(') {
			G[p].push_back(build(++s));
		} else if (*s == '*') {
			G[p].push_back(newnode());
			id[n] = ++m;
		}
		s++;
	}
	return p;
}

int f[N], g[N], R[N];
void dfs(int p) {
	if (G[p].empty()) {
		f[p] = 1;
		return;
	}
	if (!ispar[p]) {
		f[p] = 1e9;
		g[p] = -1;
		for (auto e : G[p]) {
			dfs(e);
			if (f[e] < f[p]) {
				f[p] = f[e];
				g[p] = e; 
			}
		}
	} else {
		f[p] = 0;
		for (auto e : G[p]) {
			dfs(e);
			f[p] += f[e];
		}
	}
}

void dfs1(int p) {
	if (G[p].empty()) {
		R[id[p]] = 1;
		return;
	}
	if (ispar[p]) {
		for (auto e : G[p])
			dfs1(e);
	} else {
		dfs1(g[p]);
	}
}

int main() {
	scanf("%d", &T);
	while (T--) {
		n = m = 0;
		scanf("%d", &r);
		gets(s);
		char* tmp = s;
		build(tmp);
		dfs(1);
		long long v = 1ll * r * f[1];
		for (int i = 1; i <= m; i++) {
			R[i] = 0;
		}
		dfs1(1);
		printf("REVOLTING");
		for (int i = 1; i <= m; i++)
			printf(" %lld", R[i] * v);
		putchar('\n');
	}
	return 0;
}

Problem F Intergalactic Sliding Puzzle

  考虑按顺时针的构成的环排列,不考虑空位置。

  注意到大环不会影响环排列,而空位置经过中间的隔板会做一个长度为 $2k + 1$ 的循环移位。

  不难发现必要条件是排列的逆序对个数位偶数个,因为这些循环移位均不会改变逆序对奇偶性。

  通过打表(或者阅读题解)可以构造把连续 3 个数循环位移的方案。

  然后简单构造一下就行了。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;

const int N = 128;

string operator * (string a, int t) {
	string b = "";
	for (int i = 0; i < t; i++)
		b += a;
	return b;
}
ostream& operator << (ostream& os, vector<int> p) {
	for (auto x : p)
		os << x << " ";
	os << '\n';
	return os;
}

string sl("l"), sr("r"), su("u"), sd("d");

int T, k, L, n;
int x, y;
vector<int> grid[2];
vector<int> perm;

void solve() {
	cin >> k;
	L = 2 * k + 1;
	n = 4 * k + 1;
	grid[0].resize(L);
	grid[1].resize(L);
	string _;
	for (int i = 0; i < L; i++) {
		cin >> _;
		if (_[0] == 'E') {
			grid[0][i] = -1;
			x = 0, y = i;
		} else {
			grid[0][i] = stoi(_);
		}
	}
	for (int i = 0; i < L; i++) {
		cin >> _;
		if (_[0] == 'E') {
			grid[1][i] = -1;
			x = 1, y = i;
		} else {
			grid[1][i] = stoi(_);
		}
	}
	string ans = "";
	while (x != 0 || y != k) {
		if (x == 0) {
			if (y < k) {
				ans += 'r';
				swap(grid[x][y], grid[x][y + 1]);
				y++;
			} else {
				ans += 'l';
				swap(grid[x][y], grid[x][y - 1]);
				y--;
			}
		} else {
			if (!y) {
				ans += 'u';
				swap(grid[x][y], grid[x - 1][y]);
				x--;
			} else {
				ans += 'l';
				swap(grid[x][y], grid[x][y - 1]);
				y--;
			}
		}
	}
	perm.clear();
	reverse(grid[1].begin(), grid[1].end());
	for (auto x : grid[0])
		if (x > 0)
			perm.push_back(x);
	for (auto x : grid[1])
		if (x > 0)
			perm.push_back(x);
	for (auto &x : perm)
		if (x > L)
			x = n - (x - L) + 1;
	int inv = 0;
	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {
			if (perm[i] > perm[j]) {
				inv ^= 1;
			}
		}
	}
	if (inv) {
		cout << ("SURGERY FAILED") << '\n';
		return;
	}
	auto rotateL = [&] () {
		rotate(perm.begin(), perm.begin() + 1, perm.end());
		ans += "A";
	};
	auto rotateR = [&] () {
		rotate(perm.begin(), perm.end() - 1, perm.end());
		ans += "B";
	};
	auto shift3 = [&] () {
		swap(perm[0], perm[2]);
		swap(perm[1], perm[2]);
		ans += "S";
	};
	string A = sr * k + sd + sl * (L - 1) + su + sr * k;
	string B = sl * k + sd + sr * (L - 1) + su + sl * k;
	string C = sr * k + sd + sl * k + su;
	string D = sd + sr * k + su + sl * k;
	string S = string("B") * (k - 1) + "CBCADD" + string("A") * (k - 1);
	while (perm[0] != 1)
		rotateR();
	for (int i = 2; i <= n - 2; i++) {
		int d = -1;
		while (perm[0] != i)
			d++, rotateL();
		if (d & 1) {
			if (perm[1] == 1) {
				rotateR(), rotateR();
				shift3(), shift3();
				d--;
				rotateL();
			} else if (perm[2] == 1) {
				rotateR();
				shift3();
				d++;
				rotateL();
				rotateL();
			} else {
				shift3();
				rotateL();
				d++;
			}
		}
		while (d) {
			rotateR(), rotateR();
			shift3();
			d -= 2;
		}
	}
	while (perm[0] != 1)
		rotateR();
	ans += sr * k + sd;
	cout << "SURGERY COMPLETE\n";
	cout << ans << '\n';
	cout << "A " << A << '\n';
	cout << "B " << B << '\n';
	cout << "C " << C << '\n';
	cout << "D " << D << '\n';
	cout << "S " << S << '\n';
	cout << "DONE\n";
}

int main() {
//	freopen("a.txt", "r", stdin);
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2019-12-18 21:04  阿波罗2003  阅读(498)  评论(0编辑  收藏  举报