Codeforces Round #843 (Div. 2)
Codeforces Round #843 (Div. 2)
https://codeforces.com/contest/1775
CD都不会写的垃圾罢了
A1. Gardener and the Capybaras (easy version)
暴力枚举分界点
#include <bits/stdc++.h>
using namespace std;
void solve () {
string s;
cin >> s;
for (int i = 0; i < s.size (); i++) {
for (int j = i + 1; j < s.size (); j++) {
//0,i i+1,j j+1,n
string a = s.substr (0, i + 1), b = s.substr (i + 1, j - i), c = s.substr (j + 1, s.size () - j);
if (max({a, b, c}) == b || min ({a, b, c}) == b) {
cout << a << ' ' << b << ' ' << c << endl;
return ;
}
}
}
cout << ":(" << endl;
}
int main () {
int t;
cin >> t;
while (t --) solve ();
}
//aab
//baa
//baaaa
A2. Gardener and the Capybaras (hard version)
分别构造 ,考虑贪心:
构造 时,要保证两端的字符串尽可能小,则左边取一个一定是最小的,即 ;
考虑右边如何最小:
- 范围内只有一种元素,即只存在 或 ,则取最后一个一定是最小,即 ;
- 否则的话,以 开头的后缀一定是最小的,则只需找到最后一个 所在位置 ,右边的串就取
这样剩下的就是中间串了,然后比较一下中间是否最大就行了。
构造 时,如果在 范围内能找到一个 的话一定能构造(这已经是最小字符串了)。
否则的话就是只有类似下面这四种情况:
不难发现这些情况都能够造出中间是 的分配方案。
所以一定有解。
#include <bits/stdc++.h>
using namespace std;
void solve () {
string s, a, b, c;
cin >> s;
int n = s.size ();
//max
a = s[0];
int find = -1, cntb = 0;
for (int i = 2; i < n; i++) {
if (s[i] == 'b') cntb ++;
}
for (int i = n - 1; i > 1; i--) {
if (s[i] == 'a') {
find = i;
break;
}
}
if (find == -1 || !cntb) {
b = s.substr (1, n - 2);
c = s[n - 1];
}
else {
int len1 = find - 1, len2 = n - find;
b = s.substr (1, len1), c = s.substr (find, len2);
}
if (b == max ({a, b, c})) {
cout << a << ' ' << b << ' ' << c << endl;
return ;
}
//min
int posa = -1;
for (int i = 1; i < n - 1; i++) {
if (s[i] == 'a') {
posa = i;
break;
}
}
if (posa != -1) {
for (int i = 0; i < posa; i++) cout << s[i];
cout << ' ' << s[posa] << ' ';
for (int i = posa + 1; i < n; i++) cout << s[i];
cout << endl;
return ;
}
cout << ":(" << endl;
}
int main () {
int t;
cin >> t;
while (t --) solve ();
}
//aab
//baa
//baaaa
B. Gardener and the Array
若不存在唯一元素(即少了他就不是全集)的元素就能构造出。
证明见:https://zhuanlan.zhihu.com/p/598160930
#include <bits/stdc++.h>
using namespace std;
void solve () {
int n, m, x;
cin >> n;
map<int, int> mp;
vector <int> v[n+1];
for (int i = 1; i <= n; i++) {
cin >> m;
for (int j = 1; j <= m; j++) {
cin >> x;
mp[x] ++;
v[i].push_back (x);
}
}
for (int i = 1; i <= n; i++) {
bool suc = true;
for (auto j : v[i]) {
mp[j] --;
if (mp[j] == 0) {
suc = false;
break;
}
mp[j] ++;
}
if (suc) {
cout << "Yes\n";
return ;
}
}
cout << "No\n";
}
int main () {
int t;
cin >> t;
while (t --) solve ();
}
//check相邻的两个数是否有包含关系
C. Interesting Sequence
位运算小结论:https://zhuanlan.zhihu.com/p/598221402
注意左移的时候1要取
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve () {
int n, m;
cin >> n >> m;
int r = 5e18 + 1, l = n; //至少为n!!
for (int i = 0; i < 60; i++) {
int a = n >> i & 1, b = m >> i & 1;
if (!a && b) {
cout << "-1\n";
return ;
}
if (!a && !b) continue;
int k = (n / (1ll << i) + 1) * (1ll << i); //>=n的最小的一个该位为0的数
//cout << k << endl;
if (a && !b) l = max (l, k);
else r = min (r, k - 1); //逐步缩小范围
}
if (r < l) cout << "-1\n";
else cout << l << endl;
}
signed main () {
int t;
cin >> t;
while (t --) solve ();
//cout << log2 (1e18);
}
//n进行二进制分解
//n上是0而x上是1, 则不可能
//m>=n
//二进制小结论: >=n的最小的一个该位为0的数: n / (1 << i) + 1
D. Friendly Spiders
图论 + 数论
挺好的一道题,学到了一个建图小技巧。
本来有 个点互相可达的话要建 条边,而如果使用下图这种建图方法的话就会将边数变为 ,把空间从 优化成
我们把 叫做虚点,对于任意一个数素因数分解之后与该因子连边即可。(为什么只看素因数? 因为包含相同素因子的点会重复连边,在造成空间冗余,而不同素因子之间一定是不相互包含的,故只需考虑素因子)
然后边权只有 两种情况,故可以使用 求最短路。
( 例题)
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 3e5 + 5, M = 2 * N;
int n, s, t, dis[M], lst[M];
vector <pii> vi[M];
int main () {
cin >> n;
//建图技巧
for (int i = 1; i <= n; i++) { //以素因子j为虚点, 就只需要建立O(n)级别的边了
int u; cin >> u;
for (int j = 2; j * j <= u; j++) {
if (u % j == 0) {
while (u % j == 0) u /= j;
vi[i].push_back ({N + j, 0});
vi[N + j].push_back ({i, 1});
}
}
if (u > 1) {
vi[i].push_back ({N + u, 0});
vi[N + u].push_back ({i, 1});
}
}
cin >> s >> t;
//0-1bfs求最短路
deque<int> q; //0放front, 1放back
q.push_back (s);
dis[s] = 1;
while (!q.empty ()) {
auto u = q.front ();
q.pop_front ();
for (auto i : vi[u]) {
int v = i.first, dist = i.second;
if (dis[v]) continue;
if (dist == 1) q.push_back (v); //1尾
else q.push_front (v); //0首
dis[v] = dis[u] + dist;
lst[v] = u; //记录前驱, 输出路径
}
}
//输出路径
if (dis[t] == 0) cout << -1;
else {
cout << dis[t] << endl;
stack<int> stk;
int ed = t;
while (ed != s) {
stk.push (ed);
ed = lst[ed];
}
stk.push (s); //别忘了把起点放进去
while (!stk.empty ()) {
auto ans = stk.top ();
if (ans < N) cout << ans << ' ';
stk.pop ();
}
}
}
E. The Human Equation
sb结论题。
https://zhuanlan.zhihu.com/p/598179357
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, x, minn, maxn, sum;
void solve () {
int n, x;
cin >> n;
minn = maxn = sum = 0;
while (n --) {
cin >> x;
sum += x;
//cout << sum << ' ';
minn = min (minn, sum), maxn = max (maxn, sum);
}
cout << maxn - minn << endl;
}
signed main () {
int t;
cin >> t;
while (t --) solve ();
}
//转化为区间和, 与0取max,min
F. Laboratory on Pluto
分类:
Codeforces