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

感觉还算有一点营养。

官方题解传送门:点我

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. I.MX6 Manufacturing Tool V2 (MFGTool2) Update Command List (UCL) User Guide translate

    Manufacturing Tool V2 (MFGTool2) Update Command List (UCL) User Guide Contents(目录) Contents(目录)     ...

  2. 2016-2017-220155329 《Java程序设计》第8周学习总结

    学号 2016-2017-220155329 <Java程序设计>第8周学习总结 教材学习内容总结 了解NIO NIO使用频道来衔接数据节点,在处理数据时,NIO可以让你设定缓冲区容量,在 ...

  3. 20155226 2016-2017-2 《Java程序设计》第8周学习总结

    20155226 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 通用API 日志 java.util.logging包提供了日志功能相关类与接口,使用日志的 ...

  4. 2065212Java实验四android开发基础

    20165212 Java实验四Android开发基础 实验内容: 1.基于Android Studio开发简单的Android应用并部署测试; 2.了解Android.组件.布局管理器的使用: 3. ...

  5. Java9的新特性

    2017.9.21延期了好几次的Java9正式发布,在人工智能的时代,java还能不能持续辉煌是个问题.看看java9的新特性没什么让自己想升级的意愿,因为要么时一些特性用不到,要么时已经有其它方案代 ...

  6. SQL Server中的事务与其隔离级别之脏读, 未提交读,不可重复读和幻读

    原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中 ...

  7. Remi 安装源

    Remi repository 是包含最新版本 PHP 和 MySQL 包的 Linux 源,由 Remi 提供维护.有个这个源之后,使用 YUM 安装或更新 PHP.MySQL.phpMyAdmin ...

  8. 黄聪:WordPress制作插件中使用wp_enqueue_script('jquery')库不起作用解决方法

    这个应该不是什么新信息,但我却是现在才搞清楚. 今天又是在wordpress调用jquery,情况还是如此.无意中打开wordpress中jquery.js,然后对比code.jquery.com中的 ...

  9. C# 与 Oracle 中 BINARY_DOUBLE数据类型查询

    Oracle 10g新增 BINARY_DOUBLE 数据类型,而.NET暂不支持这个类型,查询时需要转换为 NUMBER. eg: "SELECT RAWTOHEX(OID) AS OID ...

  10. 详解Oracle的几种分页查询语句

    转载自:http://database.51cto.com/art/200904/118737.htm 分页查询格式: SELECT * FROM (SELECT A.*, ROWNUM RN FRO ...