AtCoder Grand Contest 037 brief explanations

Start here

Problem A Dividing a String

  I guess each length no more than 2. Then dp can be.

  Finally, consider a section of a length greater than or equal to 3, if the plan to be $ 1 and $ 2 + behind the same, then classified into a $ 2 + $ 1, if the front section of the front and the same, and the front section of the front merge. After each operation will not reduce the number of segments. Such that there is an optimal embodiment each length no more than 2.

Code

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

const int N = 2e5 + 5;

template <typename T>
void vmax(T& a, T b) {
	(a < b) && (a = b, 0);
}

int n;
char s[N];
int f[N][2];

int main() {
	scanf("%s", s + 1);
	f[0][0] = 0, f[0][1] = -1e9;
	n = strlen(s + 1);
	for (int i = 1; i <= n; i++) {
		f[i][0] = f[i][1] = -1e9;
		vmax(f[i][0], f[i - 1][1] + 1);
		if (s[i] != s[i - 1])
			vmax(f[i][0], f[i - 1][0] + 1);
		if (i > 1) {
			vmax(f[i][1], f[i - 2][0] + 1);
			if (i > 3 && (s[i] != s[i - 2] || s[i - 1] != s[i - 3])) {
				vmax(f[i][1], f[i - 2][1] + 1);
			}
		}
	}
	printf("%d\n", max(f[n][0], f[n][1]));
	return 0;
}

Problem B RGB Balls

  Suppose the three colors red, green and blue by the order requirements are $ r_1, r_2, \ cdots, r_n, g_1, g_2, \ cdots, g_n, b_1, b_2, \ cdots, b_n $.

  6,187,655 $ m_i = \ min \ {r_i, b_i, g_i \}, M_i = \ max \ {r_i, b_i, g_i \} $. 猜想 answer Shi $ \ sum M_i - m_i $.

  Each given a minimum reference numerals incremented to get the ball, until proven $ k $ considered before selecting individuals at most $ k $ red balls, white balls and basketball, so the first $ k + 1 $ the individual balls to get the lowest number the reference numeral least $ m_ {k + 1} $, $ m_i it is an upper bound of $ $ I $ get individual lowest numbered balls. Similarly you can Proof of the $ i $ the individual to get the ball lower bound of the largest label is $ M_i $.

  Then according to a type of ball to greed on the line.

Code

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

#define ll long long

void exgcd(int a, int b, int& x, int& y) {
	if (!b) {
		x = 1, y = 0;
	} else {
		exgcd(b, a % b, y, x);
		y -= (a / b) * x;
	}
}

int inv(int a, int n) {
	int x, y;
	exgcd(a, n, x, y);
	return (x < 0) ? (x + n) : (x);
}

const int Mod = 998244353;

template <const int Mod = :: Mod>
class Z {
	public:
		int v;

		Z() : v(0) {	}
		Z(int x) : v(x){	}
		Z(ll x) : v(x % Mod) {	}

		friend Z operator + (const Z& a, const Z& b) {
			int x;
			return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x));
		}
		friend Z operator - (const Z& a, const Z& b) {
			int x;
			return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x));
		}
		friend Z operator * (const Z& a, const Z& b) {
			return Z(a.v * 1ll * b.v);
		}
		friend Z operator ~(const Z& a) {
			return inv(a.v, Mod);
		}
		friend Z operator - (const Z& a) {
			return Z(0) - a;
		}
		Z& operator += (Z b) {
			return *this = *this + b;
		}
		Z& operator -= (Z b) {
			return *this = *this - b;
		}
		Z& operator *= (Z b) {
			return *this = *this * b;
		}
		friend boolean operator == (const Z& a, const Z& b) {
			return a.v == b.v;
		} 
};

Z<> qpow(Z<> a, int p) {
	Z<> rt = Z<>(1), pa = a;
	for ( ; p; p >>= 1, pa = pa * pa) {
		if (p & 1) {
			rt = rt * pa;
		}
	}
	return rt;
}

typedef Z<> Zi;

const int N = 1e5 + 5;

int n;
char s[N * 3];

int main() {
	scanf("%d", &n);
	scanf("%s", s + 1);
	int r, g, b, rg, rb, gb;
	r = g = b = 0;
	rg = rb = gb = 0;
	Zi ans = 1;
	for (int i = 1; i <= n;i ++) 
		ans * = i;
	for (int i = 1; i <= 3 * n; i++) {
		if (s[i] == 'R') {
			if (gb) {
				ans *= gb--;
			} else if (g) {
				ans *= g--;
				rg++;
			} else if (b) {
				ans *= b--;
				rb++;
			} else {
				r++;
			}
		} else if (s[i] == 'G') {
			if (rb) {
				ans *= rb--;
			} else if (r) {
				ans *= r--;
				rg++;
			} else if (b) {
				ans *= b--;
				gb++;
			} else {
				g++;
			}
		} else if (s[i] == 'B') {
			if (rg) {
				ans *= rg--;
			} else if (r) {
				ans *= r--;
				rb++;
			} else if (g) {
				ans *= g--;
				gb++;
			} else {
				b++;
			}
		}
	}
	printf("%d\n", ans.v);
	return 0;
}

Problem C Numbers on a Circle

  Consider backwards to do the operation becomes a minus number on both sides and, if you can operate a number, then it can not be on both sides of the number of operations. So either it reaches its target value, or it is smaller than the number on both sides.

  Difficult to find one more time, or binary, or to reach the target value, a judgment or no solution, so the total time complexity $ O (n \ log V) $.

Code

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

const int N = 2e5 + 5;

int n;
int A[N];
int B[N];
boolean inq[N];

boolean check(int p) {
	return B[p] >= B[(p + n - 1) % n] + B[(p + 1) % n];
}

int main() {
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%d", A + i);
	}
	for (int i = 0; i < n; i++) {
		scanf("%d", B + i);
	}
	queue<int> Q;
	for (int i = 0; i < n; i++) {
		if (check(i)) {
			inq[i] = true;
			Q.push(i);
		}
	}
	long long ans = 0;
	while (!Q.empty()) {
		int p = Q.front();
		Q.pop();
		inq[p] = false;
		int pre = (p + n - 1) % n, suf = (p + 1) % n;
		int sum = B[pre] + B[suf];
		int t = max(0, (B[p] - A[p]) / sum);
		if (!t && B[p] != A[p]) {
			puts("-1");
			return 0;
		}
		ans += t;
		B[p] -= sum * t;
		if (!inq[pre] && check(pre)) {
			inq[pre] = true;
			Q.push(pre);
		}
		if (!inq[suf] && check(suf)) {
			inq[suf] = true;
			Q.push(suf);
		}
	}
	for (int i = 0; i < n; i++) {
		if (A[i] ^ B[i]) {
			puts("-1");
			return 0;
		}
	}
	printf("%lld\n", ans);
	return 0;
}

Problem D Sorting a Grid

  Consider first movement need to meet conditions: the number of objects belonging to the same line is not in the same column.

  Such a problem is equivalent to the graph coloring: YES $ $ nm points, if $ (i, j) $ and $ (x, y) $ edged adjacent if and only if they belong to the same row in the same row or belonging to a target.

  In the color change to be equal to its reference numeral column number.

  Consider each color mark. This matching can be converted into, the edge of each point as the original image, its end points are in two groups.

  This is a regular bipartite graph, it must be solvable.

Code

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

const int inf = (signed) (~0u >> 1);

typedef class Edge {
	public:
		int ed, nx, r;

		Edge() {	}
		Edge(int ed, int nx, int r) : ed(ed), nx(nx), r(r) {	}
} Edge;

typedef class MapManager {
	public:
		int *h;
		vector<Edge> E;

		MapManager() {	}
		MapManager(int n) {
			h = new int[(n + 1)];
			memset(h, -1, sizeof(int) * (n + 1));
		}
		~MapManager() {
			delete[] h;
			E.clear();
		}

		void add_edge(int u, int v, int r) {
			E.emplace_back(v, h[u], r);
			h[u] = (signed) E.size() - 1;
		}
		void add_arc(int u, int v, int r) {
			add_edge(u, v, r);
			add_edge(v, u, 0);
		}
		Edge& operator [] (int p) {
			return E[p];
		}
} MapManager;

typedef class Network {
	public:
		int S, T;
		MapManager g;

		int *d, *h;

		Network(int S, int T) : S(S), T(T), g(T) {
			d = new int[(T + 1)];
			h = new int[(T + 1)];
		}
		~Network() {
			delete[] d;
			delete[] h;
		}

		boolean bfs() {
			queue<int> Q;
			memset(d, -1, sizeof(int) * (T + 1));
			d[S] = 0;
			Q.push(S);
			while (!Q.empty()) {
				int e = Q.front();
				Q.pop();
				for (int i = g.h[e], eu; ~i; i = g[i].nx) {
					eu = g[i].ed;
					if (!g[i].r || ~d[eu])
						continue;
					d[eu] = d[e] + 1;
					Q.push(eu);
				}
			}
			return d[T] != -1;
		}
		
		int dfs(int p, int mf) {
			if (p == T || !mf)
				return mf;
			int flow = 0, f;
			for (int& i = h[p], j, e; ~i; (i != -1) && (i = g[i].nx)) {
				e = g[i].ed, j = i;
				if (g[i].r && d[e] == d[p] + 1 && (f = dfs(e, min(mf, g[i].r))) > 0) {
					g[j].r -= f;
					g[j ^ 1].r += f;
					flow += f;
					mf -= f;
					if (!mf)
						break;
				}
			}
			return flow;
		}

		int dinic() {
			int rt = 0;
			while (bfs()) {
				for (int i = 0; i <= T; i++)
					h[i] = g.h[i];
				rt += dfs(S, inf);
			}
			return rt;
		}

		void add_edge(int u, int v, int r) {
			g.add_arc(u, v, r);
		}
} Network;

const int N = 105;

int n, m;
int a[N][N];
int b[N][N];
int c[N][N];
int id[N][N];
int col[N][N];

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			scanf("%d", a[i] + j);
		}
	}
	for (int c = 1, T; c <= m; c++) {
		Network	network (0, T = n + n + 1);
		for (int i = 1; i <= n; i++)
			network.add_edge(0, i, 1);
		for (int i = 1; i <= n; i++)
			network.add_edge(i + n, T, 1);
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				if (!col[i][j]) {
					network.add_edge(i, (a[i][j] + m - 1) / m + n, 1);
					id[i][j] = (signed) network.g.E.size() - 1;
				}
			}
		}
		network.dinic();
		MapManager& g = network.g;
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				if (!col[i][j] && g[id[i][j]].r) {
					col[i][j] = c;
				}
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			b[i][col[i][j]] = a[i][j];
		}
	}
	for (int i = 1; i <= n; i++, putchar('\n')) {
		for (int j = 1; j <= m; j++) {
			printf("%d ", b[i][j]);	
			c[(b[i][j] + m - 1) / m][j] = b[i][j];
		}
	}
	for (int i = 1; i <= n; i++, putchar('\n')) {
		for (int j = 1; j <= m; j++) {
			printf("%d ", c[i][j]);	
		}
	}
	return 0;
}

Problem E Reversing and Concatenating

  Suppose the smallest characters a, if $ A $ end, it may be the number of previous $ A $ becomes $ 2 ^ {K} $ times, first with a single operation or that it at the end.

  You find that the length $ a $ to reach this long, the program is unique.

  You may begin the enumeration of strings, this has at most $ O (n) $ a. Calculated directly on the line.

Code

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

const int N = 5005;

int n, K;
int mxR[N];
char s[N << 1], t[N], ans[N];

void check(char* s, int k, char min_c) {
	int L = 0, p = n;
	while (s[n - L] == min_c)
		L++, p--;
	L <<= k;
	if (L >= n) {
		for (int i = 1; i <= n; i++)
			putchar(min_c);
		putchar('\n');
		exit(0);
	}
	for (int i = 1; i <= L; i++) {
		t[i] = min_c;
	}
	for (int i = L + 1; i <= n; i++)
		t[i] = s[p--];
	for (int i = 1; i <= n; i++)
		if (t[i] ^ ans[i]) {

	for (int i = 1, j = 1; i <= n; i = j) {
		if (s[i] != x) {
			j++;
			continue;
		}
		while (s[j] == s[i])
			j++;
		mxR[i] = j - i;
		mxL = max(mxL, mxR[i]);
	}
	for (int i = 1; i <= n; i++) {
		if (mxR[i] == mxL) {
			check(s + (n - i + 1), K - 1, x);
		}
	}
	puts(ans + 1);
	return 0;
}

Problem F Counting of Subarrays

  Can put the problem into, you can choose the number of at least $ l $, they synthesized a number, ask how many intervals can synthesize a number there.

  Consider how to determine the feasibility of a range:

  • Takes the minimum contiguous block elements $ X $, assuming a length L $ $, it can be synthesized up to $ \ lfloor L / l \ rfloor $ a $ x + 1 $.
  • Recursively.

  Consider how to calculate the number of, the synthesis interval is considered a minimum possible number of times it is calculated.

  Suppose the current minimum sequence of digital $ X $, the minimum number for each calculation can be synthesized $ x + 1 $ the number of sections, the successive sections and shrunk to $ X $ plurality $ x + 1 $.

  To calculate the composite digital $ x + 1 $ the number of sections, only the selected continuous seeking at least $ L $ 1 or $ X $ $ $ a number of programs.

  In order to ensure the reduction number is not heavy, each selection corresponds the requirements of this section can not be consecutive segments comprising. The program included a number minus. Within this period is then calculated continuously generated $ k $ a $ x + possible points left and right points of $ 1.

  Time complexity $ O (n \ log n) $

Code

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

const int N = 2e5 + 5;

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

typedef class Segment {
	public:
		int l, r, x, y;

		Segment() {	}
		Segment(int l, int r, int x, int y) : l(l), r(r), x(x), y(y) {	}

		boolean operator < (Segment b) const {
			return l < b.l;
		}
} Segment;

int n, L;
int a[N];
pii b[N];

ll calc(vector<pii>& a) {
	ll ret = 0, sum = 0;
	for (int l = 0, r = L - 1; r < (signed) a.size(); l++, r++) {
		ret += (sum += a[l].first) * a[r].second;
	}
	return ret;
}

ll ans = 0;
int main() {
	scanf("%d%d", &n, &L);
	for (int i = 1; i <= n; i++) {
		scanf("%d", a + i);
		b[i] = pii(a[i], i);
	}
	ans = n;
	sort(b + 1, b + n + 1);
	int pos = 1, val;
	vector<Segment> vcur, vnxt, vadd;
	while (true) {
		if (!vcur.size()) {
			if (pos > n) {
				break;
			} else {
				val = b[pos].first;
			}
		} else {
			val++;
		}
//		cerr << pos << " " << val << '\n';
		vadd.clear();
		while (pos <= n && b[pos].first == val)
			vadd.emplace_back(b[pos].second, b[pos].second, 1, 1), pos++;
		vnxt.resize(vcur.size() + vadd.size());
		merge(vcur.begin(), vcur.end(), vadd.begin(), vadd.end(), vnxt.begin());
		swap(vcur, vnxt);
		vnxt.clear();
		int num = vcur.size();
		for (int i = 0, j = 0; i < num; i = ++j) {
			while (j < num - 1 && vcur[j].r + 1 == vcur[j + 1].l)
				j++;
			int len = j - i + 1, cnt = len / L;
			if (cnt) {
				vector<pii> tmp;
				for (int k = i; k <= j; k++)
					tmp.emplace_back(vcur[k].x, vcur[k].y);
				ans += calc(tmp);
				tmp.clear();
				tmp.resize(cnt, pii(0, 0));
				for (int k = L - 1; k < len; k++) {
					tmp[cnt - (k - L + 1) / L - 1].first += vcur[j - k].x;
				}
				for (int k = L - 1; k < len; k++) {
					tmp[(k - L + 1) / L].second += vcur[i + k].y;
				}
				ans -= calc(tmp);
				for (int k = 0; k < cnt; k++)
					vnxt.emplace_back(vcur[i].l + k, vcur[i].l + k, tmp[k].first, tmp[k].second);
				vnxt.back().r = vcur[j].r;
			}
		}
		swap(vcur, vnxt);
		vnxt.clear();
	}
	printf("%lld\n", ans);
	return 0;
}

Guess you like

Origin www.cnblogs.com/yyf0309/p/11619998.html