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;
}