CF 990 Educational Codeforces Round 45
既然补了就简单记录一下。
感觉还算有一点营养。
官方题解传送门:点我
A 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
B 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
C 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
D 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
E 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
F 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
G 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的更多相关文章
- Educational Codeforces Round 45 (Div 2) (A~G)
目录 Codeforces 990 A.Commentary Boxes B.Micro-World C.Bracket Sequences Concatenation Problem D.Graph ...
- 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 ...
- Educational Codeforces Round 45 (Rated for Div. 2) E - Post Lamps
E - Post Lamps 思路:一开始看错题,以为一个地方不能重复覆盖,我一想值这不是sb题吗,直接每个power check一下就好....复杂度nlogn 然后发现不是,这样的话,对于每个po ...
- Educational Codeforces Round 45 (Rated for Div. 2) G - GCD Counting
G - GCD Counting 思路:我猜测了一下gcd的个数不会很多,然后我就用dfs回溯的时候用map暴力合并就好啦. 终判被卡了MLE..... 需要每次清空一下子树的map... #inc ...
- Educational Codeforces Round 45 (Rated for Div. 2) F - Flow Control
F - Flow Control 给你一个有向图,要求你给每条边设置流量,使得所有点的流量符合题目给出的要求. 思路:只有在所有点的流量和为0时有解,因为增加一条边的值不会改变所有点的总流量和, 所以 ...
- Educational Codeforces Round 45 (Rated for Div. 2)
A bracket sequence is a string containing only characters "(" and ")". A regular ...
- Educational Codeforces Round 45
A. 一个小模拟 不解释 //By SiriusRen #include <bits/stdc++.h> using namespace std; long long n,m,a,b ...
- [Educational Codeforces Round 16]E. Generate a String
[Educational Codeforces Round 16]E. Generate a String 试题描述 zscoder wants to generate an input file f ...
- [Educational Codeforces Round 16]D. Two Arithmetic Progressions
[Educational Codeforces Round 16]D. Two Arithmetic Progressions 试题描述 You are given two arithmetic pr ...
随机推荐
- BZOJ3270: 博物馆【概率DP】【高斯消元】
Description 有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆.这座博物馆有着特别的样式.它包含由m条走廊连接的n间房间,并且满足可以从任何一 ...
- Nginx配置IPv6端口监听及务器设置IPV6及Https支持并通过AppStore审核
一.监听端口 从Nginx 1.3的某个版本起,默认ipv6only是打开的,所以,我们只需要在监听中加入ipv6监听即可,不过推荐都手动加上比较好,代码如下: listen [::]: ipv6on ...
- 【传输协议】http协议GET与POST传递数据的最大长度能够达到多少
各种web开发语言中,各个页面之间基本都会进行数据的传递,web开发里面比较常用的数据传递方式有get post,一直以来我都只知道get传递的数据量要比post传递的数据量要少,所以传递大数据量还是 ...
- 自定义简单的struts2的s标签
一:自定标签前需要了解的知识: BodyTagSupport类的方法: 编写标签对应的实现类时,需要重载BodyTagSupport类几个方法:doStartTag(), setBodyContent ...
- HTML5 Geolocation用来定位用户的位置。
HTML5 Geolocation用来定位用户的位置. 定位用户的位置 HTMl5 Geolocation API用来得到用户的地理位置. 由于这个可能和个人隐私相关.除非用户同意否则不能使用. 浏览 ...
- 浅谈ASP.NET ---- 系列文章
[01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作篇)(下) [04]浅谈ASP. ...
- sysbench 测试mysql性能
===== #1sysbench --test=oltp --oltp-table-size=10000 --mysql-db=test --mysql-user=root --mysql-passw ...
- CentOS查看显卡及GPU相关信息
lspci | grep -i vga 这样就可以显示机器上的显卡信息,比如 [root@localhost conf]# lspci | grep -i vga01:00.0 VGA compat ...
- 复制mysql数据库的步骤
Navicat 转存sql文件 然后命令 mysql -uroot -p123456 dbname < e:/backup/20141014.sql
- 内存泄漏检测工具VLD在VS2010中的使用举例
Visual LeakDetector(VLD)是一款用于Visual C++的免费的内存泄露检测工具.它的特点有:(1).它是免费开源的,采用LGPL协议:(2).它可以得到内存泄露点的调用堆栈,可 ...