既然补了就简单记录一下。

感觉还算有一点营养。

官方题解传送门:点我

Commentary Boxes

对拆掉$n \mod m$个和新建$m - (n \mod m)$求个最小。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll; int main() {
ll n, m, a, b, r;
scanf("%lld%lld%lld%lld", &n, &m, &a, &b);
r = n % m;
printf("%lld\n", min(b * r, (m - r) * a));
return ;
}

A

Micro-World

对所有数排序,从小到大扫,能吃就吃。

一个细菌如果不被刚好比它大的那个吃掉,那么再大一点的也不能吃掉。

注意到相同的数可能处理起来有一点问题,像我这种懒人就直接开个$map$当平衡树用。

#include <cstdio>
#include <cstring>
#include <map>
using namespace std; int n, k;
map <int, int> mp; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for (; ch > ''|| ch < ''; ch = getchar())
if (ch == '-') op = -;
for (; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} int main() {
read(n), read(k);
for (int v, i = ; i <= n; i++) {
read(v);
++mp[v];
} map <int, int> :: iterator lst = mp.begin(), now = mp.begin();
++now;
int ans = ;
for (; now != mp.end(); ++lst, ++now)
if (now -> first <= lst -> first + k) ans += lst -> second; printf("%d\n", n - ans);
return ;
}

B

Bracket Sequences Concatenation Problem

话说最近的几场中有类似的题目啊。

一个括号序列在自身匹配完之后一定能表示成若干个右括号$+$若干个左括号(比如$))))(((($)的形式,两个括号序列接起来能匹配的充要条件是:

1、前面的那个没有多余的右括号。

2、后面的那个没有多余的左括号。

3、前面的左括号和后面的右括号个数相同。

开个$map$正反扫一扫,注意不要忘记计算一个括号序列自身可能的贡献。

#include <cstdio>
#include <cstring>
#include <map>
#include <iostream>
using namespace std;
typedef pair <int, int> pin;
typedef long long ll; const int N = 3e5 + ; int n;
pin a[N];
char s[N];
map <int, int> mp; int main() {
scanf("%d", &n);
for (int i = ; i <= n; i++) {
scanf("%s", s + );
int len = strlen(s + ), top = ;
for (int j = ; j <= len; j++) {
if (s[j] == '(') ++top;
else {
if (top) --top;
else ++a[i].first;
}
}
if (top != ) a[i].second += top;
} ll ans = ;
for (int i = ; i <= n; i++) {
if (a[i].second == ) ans += mp[a[i].first];
if (a[i].first == ) ++mp[a[i].second];
} mp.clear();
for (int i = n; i >= ; i--) {
if (a[i].second == ) ans += mp[a[i].first];
if (a[i].first == ) ++mp[a[i].second];
} for (int i = ; i <= n; i++)
if (a[i].first == && a[i].second == ) ++ans; printf("%lld\n", ans);
return ;
}

C

Graph And Its Complement

我觉得这是这场最有趣的一道题。

做出这个首先需要发现一条性质,$n, a, b$一定需要满足$a == 1$或者$b == 1$的形式才可能有解。

可能的意思是说在$a == 1$并且$b == 1$并且$n == 2 || n == 3$的时候无解。

假设原图有超过$1$个连通块,那么对于任意两个联通块来说,取补集之后都会有一条边相连,所以补图一定只有一个连通块。

如果$b$为$1$并且$a$不为$1$可以$swap$过来然后输出补图。

这样子把$1$到$n - a + 1$连成一条链就好了。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int N = ; int n, a, b;
bool ans[N][N]; int main() {
scanf("%d%d%d", &n, &a, &b);
if (a != && b != ) return puts("NO"), ;
if (a == && b == ) {
if (n == || n == ) return puts("NO"), ;
for (int i = ; i < n; i++) ans[i][i + ] = ans[i + ][i] = ;
puts("YES");
for (int i = ; i <= n; i++, putchar('\n'))
for (int j = ; j <= n; j++)
putchar(ans[i][j] + '');
return ;
} bool flag = ;
if (a == ) swap(a, b), flag = ;
if (flag) memset(ans, , sizeof(ans));
for (int i = ; i <= n - a; i++) ans[i][i + ] ^= , ans[i + ][i] ^= ; puts("YES");
for (int i = ; i <= n; i++, putchar('\n'))
for (int j = ; j <= n; j++) {
if (i == j) putchar('');
else putchar(ans[i][j] + '');
} return ;
}

D

Post Lamps

这题我纠结了很长时间的第一个样例,因为怎么玩都有比样例输出更好的答案,直到我在$announcement$里面发现了这样一句话:

感觉无话可说……

先考虑没有“不能放”的限制的时候怎么做,对于每一个亮度$k$,贪心地把它放在$0, k, 2k, \cdots$直到大于等于$n$。

现在加入限制条件,考虑如果在跳的时候遇到了一个障碍,就尝试在这个障碍前面最近的一个不是障碍的位置放灯,如果这样还是不可以照亮它,那么直接无解。

障碍在$0$的时候可以直接无解。

可以用一个并查集,遇到障碍就把父指针指向前一个位置,这个并查集可以路径压缩。

注意到这个复杂度其实是一个调和级数,虽然并不是特别严格,但是根本跑不满。

应该比$D$简单吧。

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = 1e6 + ;
const ll inf = 1LL << ; int n, m, k, ufs[N];
ll a[N];
bool b[N]; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for (; ch > ''|| ch < ''; ch = getchar())
if (ch == '-') op = -;
for (; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} template <typename T>
inline void chkMin(T &x, T y) {
if (y < x) x = y;
} int find(int x) {
return ufs[x] == x ? x : ufs[x] = find(ufs[x]);
} int main() {
read(n), read(m), read(k);
for (int i = ; i <= n; i++) ufs[i] = i;
for (int pos, i = ; i <= m; i++) {
read(pos);
if (pos == ) return puts("-1"), ;
b[pos] = ;
ufs[pos] = pos - ;
}
b[n] = , ufs[n] = n - ;
for (int i = ; i <= k; i++) read(a[i]); ll ans = inf;
for (int i = ; i <= k; i++) {
int cnt = ; ll res = ;
for (int j = ; j < n; j += i) {
if (!b[j]) ++cnt;
else {
int pos = find(ufs[j]);
if (j - pos < i) ++cnt, j = pos;
else {
res = inf;
break;
}
}
}
if (res != inf) res = 1LL * cnt * a[i];
chkMin(ans, res);
} printf("%I64d\n", ans == inf ? - : ans);
return ;
}

E

Flow Control

虽然网络流已经差不多忘得一干二净了,但是流量守恒这一点还是能记住手玩出来的。

先把所有的$s_i$求和,如果不为$0$一定不合法。

注意到当有环的时候有一些边可以随便流,等价于就算这些边不存在(流量为$0$)也能出解。

所以做一棵生成树就好了,不在生成树中的边流量输出$0$。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
typedef pair <int, int> pin; const int N = 2e5 + ; int n, m, tot = , head[N], ufs[N], dep[N];
ll a[N], sum[N];
bool vis[N];
pin pat[N]; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for (; ch > ''|| ch < ''; ch = getchar())
if (ch == '-') op = -;
for (; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} int find(int x) {
return ufs[x] == x ? x : ufs[x] = find(ufs[x]);
} inline bool merge(int x, int y) {
int fx = find(x), fy = find(y);
if (fx == fy) return ;
ufs[fx] = fy;
return ;
} inline bool chk() {
ll tmp = ;
for (int i = ; i <= n; i++) tmp += a[i];
return (!tmp);
} void dfs(int x, int fat, int depth) {
dep[x] = depth, sum[x] = a[x];
for (int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if (y == fat) continue;
dfs(y, x, depth + );
sum[x] += sum[y];
}
} int main() {
read(n);
for (int i = ; i <= n; i++) {
read(a[i]);
ufs[i] = i;
}
read(m);
for (int x, y, i = ; i <= m; i++) {
read(x), read(y);
pat[i].first = x, pat[i].second = y;
if (!merge(x, y)) continue;
vis[i] = ;
add(x, y), add(y, x);
} if (!chk()) return puts("Impossible"), ; dfs(, , ); puts("Possible");
for (int i = ; i <= m; i++) {
if (vis[i])
printf("%lld\n", dep[pat[i].first] < dep[pat[i].second] ? sum[pat[i].second] : -sum[pat[i].first]);
else puts("");
} return ;
}

F

GCD Counting

因为统计的时候复杂度是只和$gcd$的个数有关的,所以可以直接大力点分治,复杂度也是没问题的。

但是点分治真的写不对这样太无脑了,考虑正解提到的稍微有一点技术含量的做法。

用$h(i)$表示树上能被$i$整除的路径的数量,注意到在树上一定是若干个满足条件的联通块选点之后求和。

一个$siz$为$n$的连通块的贡献是$\frac{n(n + 1)}{2}$。

那么最后的答案

$$ans_x = \sum_{i = x}^{\left \lfloor \frac{n}{x} \right \rfloor}\mu(i)h(xi)$$

我选择用一个并查集合并一下。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll; const int N = 2e5 + ;
const int Maxn = 2e5; int n, a[N], tot = , head[N], fa[N];
int pCnt = , pri[N], mu[N], ufs[N], siz[N];
bool np[N], vis[N];
ll ans[N], f[N];
vector <int> h[N], vec; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for (; ch > ''|| ch < ''; ch = getchar())
if (ch == '-') op = -;
for (; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void sieve() {
mu[] = ;
for (int i = ; i <= Maxn; i++) {
if (!np[i])
pri[++pCnt] = i, mu[i] = -;
for (int j = ; j <= pCnt && pri[j] * i <= Maxn; j++) {
np[i * pri[j]] = ;
if (i % pri[j] == ) {
mu[i * pri[j]] = ;
break;
}
mu[i * pri[j]] = -mu[i];
}
}
} void dfs(int x, int fat) {
fa[x] = fat;
for (int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if (y == fat) continue;
dfs(y, x);
}
} int find(int x) {
return ufs[x] == x ? x : ufs[x] = find(ufs[x]);
} inline bool merge(int x, int y) {
int fx = find(x), fy = find(y);
if (fx == fy) return ;
if (siz[fx] < siz[fy]) ufs[fx] = fy, siz[fy] += siz[fx];
else ufs[fy] = fx, siz[fx] += siz[fy];
return ;
} int main() {
sieve(); read(n);
for (int i = ; i <= n; i++) {
read(a[i]);
h[a[i]].push_back(i);
}
for (int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
}
dfs(, ); for (int i = ; i <= Maxn; i++) {
for (int j = i; j <= Maxn; j += i)
for (int k = ; k < (int)h[j].size(); k++) {
int x = h[j][k];
ufs[x] = x, siz[x] = , vis[x] = ;
vec.push_back(x);
} for (int j = ; j < (int)vec.size(); j++) {
int x = vec[j];
if (fa[x] && a[fa[x]] % i == ) merge(x, fa[x]);
} for (int j = ; j < (int)vec.size(); j++) {
int x = vec[j], fx = find(x);
if (vis[fx]) continue;
f[i] += 1LL * siz[fx] * (siz[fx] + ) / ;
vis[fx] = ;
} vec.clear();
} for (int i = ; i <= Maxn; i++)
for (int j = i; j <= Maxn; j += i)
ans[i] += 1LL * mu[j / i] * f[j]; for (int i = ; i <= Maxn; i++) {
if (!ans[i]) continue;
printf("%d %I64d\n", i, ans[i]);
} return ;
}

G

CF 990 Educational Codeforces Round 45的更多相关文章

  1. Educational Codeforces Round 45 (Div 2) (A~G)

    目录 Codeforces 990 A.Commentary Boxes B.Micro-World C.Bracket Sequences Concatenation Problem D.Graph ...

  2. Educational Codeforces Round 45 (Rated for Div. 2) C、D

      C. Bracket Sequences Concatenation Problem time limit per test 2 seconds memory limit per test 256 ...

  3. Educational Codeforces Round 45 (Rated for Div. 2) E - Post Lamps

    E - Post Lamps 思路:一开始看错题,以为一个地方不能重复覆盖,我一想值这不是sb题吗,直接每个power check一下就好....复杂度nlogn 然后发现不是,这样的话,对于每个po ...

  4. Educational Codeforces Round 45 (Rated for Div. 2) G - GCD Counting

    G - GCD Counting 思路:我猜测了一下gcd的个数不会很多,然后我就用dfs回溯的时候用map暴力合并就好啦. 终判被卡了MLE.....  需要每次清空一下子树的map... #inc ...

  5. Educational Codeforces Round 45 (Rated for Div. 2) F - Flow Control

    F - Flow Control 给你一个有向图,要求你给每条边设置流量,使得所有点的流量符合题目给出的要求. 思路:只有在所有点的流量和为0时有解,因为增加一条边的值不会改变所有点的总流量和, 所以 ...

  6. Educational Codeforces Round 45 (Rated for Div. 2)

    A bracket sequence is a string containing only characters "(" and ")". A regular ...

  7. Educational Codeforces Round 45

    A. 一个小模拟    不解释 //By SiriusRen #include <bits/stdc++.h> using namespace std; long long n,m,a,b ...

  8. [Educational Codeforces Round 16]E. Generate a String

    [Educational Codeforces Round 16]E. Generate a String 试题描述 zscoder wants to generate an input file f ...

  9. [Educational Codeforces Round 16]D. Two Arithmetic Progressions

    [Educational Codeforces Round 16]D. Two Arithmetic Progressions 试题描述 You are given two arithmetic pr ...

随机推荐

  1. PTA编程总

    7-1 币值转换 (20 分) 输入一个整数(位数不超过9位)代表一个人民币值(单位为元),请转换成财务要求的大写中文格式.如23108元,转换后变成“贰万叁仟壹百零捌”元.为了简化输出,用小写英文字 ...

  2. MyBatis_Study_003(字段名与属性名称不一致,resultMap)

    源码:https://github.com/carryLess/mbtsstd-003 1.主配置文件 <?xml version="1.0" encoding=" ...

  3. 使用mongoperf评估磁盘随机IO性能

    用法举例: # 16个io线程 # 随机读写10GB的测试文件 echo "{nThreads:16,fileSizeMB:10000,r:true,w:true}" | mong ...

  4. linux sort 多列正排序,倒排序

    转载:https://segmentfault.com/a/1190000005713784 sort是在Linux里非常常用的一个命令,管排序 sort将文件的每一行作为一个单位,相互比较,比较原则 ...

  5. coredns 代理consul 运行noamd 部署的应用

    nomad 是一个方便的应用调度平台,consul 一个很不错的服务发现工具,coredns 很不错, 扩展性比较强的dns 服务器,集成起来可能做很强大的事情 我的运行环境是mac,实际情况按需部署 ...

  6. Python程序,辅助微信跳一跳游戏介绍

    一.思路介绍 1. 通过Python自动手机截屏,并保存到电脑 2. 通过PhotoShop测量要跳的距离 3. 通过Excel计算按压时间 4. 通过CMD命令控制手机按压时间 二.实现方法详解 1 ...

  7. 如何查看MySql的BLOB内容

    一款Mysql的工具: SQLyog. 强项在于可以把blob的内容直接显示出来. 我觉得其实做产品能够活挺厉害,因为你做的东西确实为客户提供价值:在云云产品之中,能够让客户发现你并使用,购买你的产品 ...

  8. week2--线性表

    一.PTA实验作业 题目1:顺序表删除重复元素(6-3) 设计思路 代码截图 PTA提交列表说明 编译错误:写'->'符号的时候总是漏掉'>'; 写'!='符号的时候漏写'!'; 解决方法 ...

  9. 八、jdk工具之JvisualVM、JvisualVM之二--Java程序性能分析工具Java VisualVM

    目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...

  10. ffmpeg重要的参考学习网址

    http://lib.csdn.net/liveplay/knowledge/1586 FFmpeg滤镜使用指南 http://blog.csdn.net/fireroll/article/detai ...