Educational Codeforces Round 145 (Rated for Div. 2) - 题解

https://codeforces.com/contest/1809/problems

A. Garland

只需要枚举颜色种类数即可。如果颜色为 \(2\) 还要枚举一下颜色分布,形如 aabb 的答案为 \(4\),形如 abbb 的答案为 \(6\),如果形如 aaaa 无解,否则答案均为 \(4\)

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
//#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
int mp[10], gs[10];
signed main () {
	int t;
	scanf ("%d", &t);
	while (t --) {
		string s;
		cin >> s;
		for (int i = 0;i < 10; ++ i) mp[i] = 0, gs[i] = 0;
		for (int i = 0;i < 4; ++ i) mp[s[i] - '0'] = 1, gs[s[i] - '0'] ++;
		int kind = 0;
		for (int i = 0;i < 10; ++ i) kind += mp[i];
		if (kind == 1) printf ("-1\n");
		if (kind == 2) {
			int mx = 0;
			for (int i = 0;i < 10; ++ i) mx = max (mx, gs[i]);
			if (mx == 3) printf ("6\n");
			else printf ("4\n");
		}
		if (kind == 3 || kind == 4) printf ("4\n");
	}
	return 0;
}

B. Points on Plane

容易发现答案为 \(\lfloor\sqrt{n}\rfloor\),如果 \(n=m^2(m \in \mathbb{Z})\) 答案还要减去 \(1\)

具体为什么可以举个例子画画图(比如样例给的数 & \(4\)),可以将 \(|x|+|y|\leq k\)\((x,y)\) 都画出来找找规律,画出来发现点数量是平方数。

如果发现某些比较反常的特例,务必在想一想类似的数据。

突破口:

\(\lfloor\sqrt{975461057789971042}\rfloor=987654321\)

\(\lfloor\sqrt{5}\rfloor=2\)

\(\lfloor\sqrt{3}\rfloor=1\)

\(\lfloor\sqrt{1}\rfloor-1=0\)

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
signed main () {
	int _;
	scanf ("%lld", &_);
	while (_ --) {
		int x;
		scanf ("%lld", &x);
		int qwq = (int) (sqrt (x));
		while (qwq * qwq > x) qwq --;
		while ((qwq + 1) * (qwq + 1) <= x) qwq ++;
		if (qwq * qwq == x) printf ("%lld\n", qwq - 1);
		else printf ("%lld\n", qwq);
	}
	return 0;
}

C. Sum on Subarrays

一道妙构造。

可以发现,长度为 \(l\)全都是正数的序列可以产生 \(\dfrac{l^2+l}{2}\)和为正数的序列的贡献。

那么找出满足 \(\dfrac{l^2+l}{2} \leq k\) 的最大的 \(l\)

发现还需要 \(k'=k-\dfrac{l^2+l}{2}\) 个和为正数的序列。

我们令前 \(l\) 个数都填 \(2\)。(为什么非得填 \(2\)?填 \(1\) 不行吗?这个一会讲到原理会解释)

关键的来了,让第 \(l+1\) 个数为 \(2(k'-(l+1))+1\)

\([1,l+1],[2,l+1],\dots,[l,l+1]\) 中,和为负的有 \(l-k'\) 个(加上 \(2\times(l-k')\) 后和为 \(-1\),再加 \(2\) 后和为 \(1\)),那么和为正的就有 \(k'\) 个,满足条件。

为什么要填 \(2\),为的就是避免出现子段和为 \(0\) 的情况。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
//#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
signed main () {
	int _;
	scanf ("%d", &_);
	while (_ --) {
		int n, k;
		scanf ("%d %d", &n, &k);
		for (int i = 1;i <= n; ++ i) {
			if (k >= i) printf ("2 "), k -= i;
			else if (k != 0) printf ("%d ", 2 * (k - i) + 1), k = 0;
			else printf ("-1000 ");
		} 
		printf ("\n");
	}
	return 0;
}

D. Binary String Sorting

我们可以发现,最后的满足条件的序列一定是若干(可以为 \(0\))个 \(0\) 连着若干(也可以为 \(0\))个 \(1\)

可以枚举分界点 \(i\),即 \([1,i]\) 删除后均为 \(0\)\([i+1,n]\) 删除后均为 \(1\),将不满足条件的都删掉。

每次都用 \(10^{12}+1\) 未必有点太浪费了,如果 \(s_i=0\)\(s_{i+1}=1\),那么可以将删除变为交换,省掉 \(10^{12}+2\) 的花费。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
const int C = 1e12;
int n, s0[300005], s1[300005];
char s[300005];
signed main () {
	int _;
	scanf ("%lld", &_);
	while (_ --) {
		scanf ("%s", s + 1);
		n = strlen (s + 1);
		int ans = 9e18;
		for (int i = 1;i <= n; ++ i) {
			s0[i] = s0[i - 1] + (s[i] == '0');
			s1[i] = s1[i - 1] + (s[i] == '1');
		}
		for (int i = 0;i <= n; ++ i) {
			if (i < n && s[i] == '1' && s[i + 1] == '0') {
				int tmp = (C + 1) * (s1[i] + s0[n] - s0[i]);
				tmp -= 2 * (C + 1);
				tmp += C;
				ans = min (ans, tmp);
			}
			else {
				int tmp = (C + 1) * (s1[i] + s0[n] - s0[i]);
				ans = min (ans, tmp);
			}
		}
		printf ("%lld\n", ans);
	}
	return 0;
}

E. Two Tanks

不难发现,每一条从右上到左下的线(比如样例一有一条就是:\((0,4),(1,3),(2,2),(3,1),(4,0)\))的答案都是以下形式:\([L,L,\dots,L,L+1,L+2,\dots,R,R,\dots,R]\)

不难直接暴力算出每条右上到左下的线 \(L,R\) 的值,二分算出答案\(L,R\) 的范围,最后一赋值就行。

算单个答案直接暴力,实测 1.4s。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
//#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
int n, v[10005], a, b, ans[1005][1005];
inline int run (int x, int y) {
	for (int i = 1;i <= n; ++ i) {
		if (v[i] > 0) {
			int qwq = min ({x, b - y, v[i]});
			x -= qwq;
			y += qwq;
		}
		else {
			int qwq = min ({a - x, y, -v[i]});
			x += qwq;
			y -= qwq; 
		}
	}
	return x;
}
signed main () {
	scanf ("%d %d %d", &n, &a, &b);
	for (int i = 1;i <= n; ++ i) scanf ("%d", &v[i]);
	for (int S = 0;S <= a + b; ++ S) {
		int lo, hi;
		if (S <= b) lo = 0;
		else lo = S - b;
		if (S <= a) hi = S;
		else hi = a;
		int ans_lo = run (lo, S - lo), ans_hi = run (hi, S - hi);
		if (ans_lo == ans_hi) {
			for (int i = lo;i <= hi; ++ i) ans[i][S - i] = ans_lo;
			continue;
		}
		int lto = -1, rto = -1;
		int L = lo, R = hi;
		while (R - L > 1) {
			int mid = L + R >> 1;
			if (run (mid, S - mid) == ans_lo) L = mid;
			else R = mid;
		}
		if (run (R, S - R) == ans_lo) lto = R;
		else lto = L;
		L = lo, R = hi;
		while (R - L > 1) {
			int mid = L + R >> 1;
			if (run (mid, S - mid) == ans_hi) R = mid;
			else L = mid;
		}
		if (run (L, S - L) == ans_hi) rto = L;
		else rto = R;
		for (int i = lo;i <= lto; ++ i) ans[i][S - i] = ans_lo;
		for (int i = rto;i <= hi; ++ i) ans[i][S - i] = ans_hi;
		for (int i = lto + 1;i < rto; ++ i) ans[i][S - i] = ans_lo + i - lto; 
	}
	for (int i = 0;i <= a; ++ i) {
		for (int j = 0;j <= b; ++ j) {
			printf ("%d ", ans[i][j]);
		}
		printf ("\n");
	}
	return 0;
}
posted @ 2023-03-24 22:34  CountingGroup  阅读(154)  评论(0编辑  收藏  举报