May Cook-Off 2019 解题报告
太气了。Atcoder unrated了。
这一场时间太不友好了。昨天下午一时兴起就去补了一发。题很好,学到好多东西。
题意:给一个矩阵,这个矩阵是稳定的当且仅当每一个元素都是稳定的。元素是稳定的当且仅当它的值严格小于它相邻有几个元素
思路:四个角的值就必须小于2,然后外圈的其他数的值就必须小于3,其他的就必须小于4。
#include <bits/stdc++.h>
using namespace std; inline int read() {
int x = , f = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') f = -; ch = getchar(); }
while (ch >= '' && ch <= '') { x = x * + ch - ; ch = getchar(); }
return x * f;
} const int N = ;
int a[N][N]; int main() {
int T = read();
while (T--) {
int r = read(), c = read();
bool ans = false;
for (int i = ; i <= r; i++) {
for (int j = ; j <= c; j++) {
a[i][j] = read();
if (i == ) {
if (i == j || j == c) {
if (a[i][j] >= ) ans = true;
} else {
if (a[i][j] >= ) ans = true;
}
} else if (i == r) {
if ( == j || j == c) {
if (a[i][j] >= ) ans = true;
} else {
if (a[i][j] >= ) ans = true;
}
} else if (j == || j == c) {
if (a[i][j] >= ) ans = true;
} else {
if (a[i][j] == ) ans = true;
}
}
}
if (ans) puts("Unstable");
else puts("Stable");
}
}
题意:一个等差数列,其中一个数被改了,要求原数列。
思路:四项肯定可以出一个等差数列,只看前四项就ok了。
#include <bits/stdc++.h>
using namespace std; inline int read() {
int x = , f = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') f = -; ch = getchar(); }
while (ch >= '' && ch <= '') { x = x * + ch - ; ch = getchar(); }
return x * f;
} const int N = 1e5 + ;
int a[N], b[N]; int main() {
int T = read();
while (T--) {
int n = read();
for (int i = ; i <= n; i++) a[i] = read();
if (a[] - a[] == a[] - a[]) {
int d = a[] - a[];
for (int i = ; i <= n; i++) {
a[i] = a[i-] + d;
}
} else if (a[] - a[] == a[] - a[]) {
int d = a[] - a[];
for (int i = n - ; i > ; i--) {
a[i] = a[i+] - d;
}
} else {
int d = (a[] - a[]) / ;
for (int i = ; i <= n; i++) {
a[i] = a[i - ] + d;
}
}
for (int i = ; i <= n; i++) { if (i - ) putchar(' '); printf("%d", a[i]); }
puts("");
}
return ;
}
题意:给一个区间$l,r$和一个数$g$,要求这个区间内最多有几个数的GCD刚好为$g$
思路:容斥求,WA了好几发,原因是。当容斥出来结果只有1个时,$g$必须在$l,r$之间,不然这一个数的最大因子是自己而不是$g$。
题目描述也是The greatest positive integer which divides each element of the set is exactly $g$,一个数的greatest positive integer which divide it是它本身。
#include <bits/stdc++.h>
#define ll long long
using namespace std; inline ll readl() {
ll x = , f = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') f = -; ch = getchar(); }
while (ch >= '' && ch <= '') { x = x * + ch - ; ch = getchar(); }
return x * f;
} int main() {
ll T = readl();
while (T--) {
ll l = readl(), r = readl(), g = readl();
ll ans = r / g - l / g + (l % g == );
if (ans == ) {
if (g < l || g > r) ans = ;
}
printf("%lld\n", ans);
}
return ;
}
题意:给一个有向图,问能不能删边删点使他们成为一个二分图 一边点数为2,一边点数为$k$
思路:暴力求。不知道为啥不会T。咱也不知道,咱也不敢问。
#include <bits/stdc++.h>
using namespace std; inline int read() {
int x = , f = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') f = -; ch = getchar(); }
while (ch >= '' && ch <= '') { x = x * + ch - ; ch = getchar(); }
return x * f;
} const int N = 2e3 + ;
vector<int> G[N]; int main() {
int n = read(), m = read(), k = read();
for (int i = ; i < m; i++) {
int u = read(), v = read();
G[u].emplace_back(v);
G[v].emplace_back(u);
}
for (int i = ; i <= n; i++) sort(G[i].begin(), G[i].end());
for (int i = ; i <= n; i++) {
for (int j = i + ; j <= n; j++) {
int p1 = , p2 = ;
int ans = ;
int sz1 = G[i].size(), sz2 = G[j].size();
while (p1 < sz1 && p2 < sz2) {
if (G[i][p1] == G[j][p2]) {
p1++;p2++; ans++;
} else if (G[i][p1] < G[j][p2]) {
p1++;
} else p2++;
}
if (ans >= k) { puts("YES"); return ;}
}
}
puts("NO");
return ;
}
看了题解的解法。复杂度就比较科学了。$O\left( n^{2}k\right)$
#include <bits/stdc++.h>
using namespace std; inline int read() {
int x = , f = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') f = -; ch = getchar(); }
while (ch >= '' && ch <= '') { x = x * + ch - ; ch = getchar(); }
return x * f;
} const int N = 2e3 + ;
vector<int> G[N];
int cnt[N][N]; int main() {
int n = read(), m = read(), k = read();
for (int i = ; i < m; i++) {
int u = read(), v = read();
G[u].emplace_back(v);
G[v].emplace_back(u);
}
bool ans = false;
for (int i = ; i <= n; i++) {
if (ans) break;
for (auto x: G[i]) {
if (ans) break;
for (auto y: G[i]) {
if (x < y) {
cnt[x][y]++;
cnt[y][x]++;
}
if (cnt[x][y] >= k) {
ans = true;
break;
}
}
}
}
if (ans) puts("YES");
else puts("NO");
return ;
}
题意:给n个物品,每个物品有值$b_{i}$和选中概率$p_{i}$,求异或和的期望
思路:emmmm概率题本来就不太会再加上异或emmmmm
按位考虑每一个数,因为异或是两个相同就变成0了。那么能对期望做出贡献的时候就是二选一的时候
pro表示在当前位,当前数能对期望做出贡献的概率。
到下一个数的时候就是$pro\ast \left( 1-p_{i}\right) + p_{i}\ast \left( 1-pro\right)$
最后乘上(1 << k) 就行了 k表示当前位
#include <bits/stdc++.h>
using namespace std; inline int read() {
int x = , f = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') f = -; ch = getchar(); }
while (ch >= '' && ch <= '') { x = x * + ch - ; ch = getchar(); }
return x * f;
} const int N = 1e5 + ;
int b[N], n;
double p[N]; int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = ; i < n; i++) scanf("%d", &b[i]);
for (int i = ; i < n; i++) scanf("%lf", &p[i]);
long double ans = ;
for (int bit = ; bit < ; bit++) {
long double pro = ;
for (int i = ; i < n; i++) {
if ((b[i] >> bit) & ) {
pro = ( - pro) * (long double)p[i] + pro * ( - (long double)p[i]);
}
}
ans += ( << bit) * pro;
}
printf("%.7Lf\n", ans);
}
return ;
}
题意:有节点0到$2^{k} - 1$,给一个序列$m_{i}$ ,所有点对$u,v$ $u\oplus v = m_{i}$的之间连边,问最后有多少个连通块
思路:推了半天结论也没推明白。看题解才明白是高斯消元。
对于一个节点$u$,它能到达的点是这个序列的数,任意组合,异或之后的值的个数(加上一个0)
本来是只能异或这个序列里面的一个数,但是由于别的数也会异或,就会连通了。
比如两个节点1 和 2
$m_{1} = 1$ $m_{2} = 2$
1和$m_{1}$异或后是0 和$m_{2}$异或后是3 2和$m_{1}$异或后是3
本来只异或一个值的话,1和2看起来是不连通的
但就是会间接相连 所以就是xjb组合着去异或
然后答案就是看这个序列能异或出多少种值来。
把它们按二进制排成一个矩阵。
求出这个矩阵的秩$r$
答案就是$2^{k - r}$
解释:把矩阵通过异或运算变成行阶梯型之后,秩为$r$,前$r$行的线性组合得到的结果必是不一样了
然后取和不取种类数就是$2^{r}$种
#include <bits/stdc++.h>
using namespace std; inline int read() {
int x = , f = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') f = -; ch = getchar(); }
while (ch >= '' && ch <= '') { x = x * + ch - ; ch = getchar(); }
return x * f;
} const int N = 1e5 + ;
int a[N];
int bin[N]; int main() {
int T = read();
while (T--) {
memset(bin, , sizeof(bin));
int k = read(), m = read();
for (int i = ; i < m; i++) {
int x = read();
for (int j = ; j < ; j++) {
if ((<<j) & x) {
if (!bin[j]) {
bin[j] = x;
k--;
break;
}
x ^= bin[j];
}
}
}
cout << ( << k) << '\n';
}
return ;
}
题意:一棵树,刚开始只有根1和颜色$c$,给$Q$次询问,询问有两种,第一种是给节点$u$加上一个儿子(编号为当前节点数+1),颜色染成$c$,第二种询问颜色为$c$的节点中,和$u$最近的距离是多少。
思路:直接写了发暴力找+倍增LCA,T了。看了题解才发现有trick。
把颜色分为大和小。以300次为界限。
出现次数小于300的就可以直接暴力+LCA
大于300的把颜色为$c$的节点$u$ $dis[c][u] = 0$并且对这些节点进行bfs
bfs过程中若dis为INF的话就可以更新成$dis[c][u] + 1$
#include <bits/stdc++.h>
using namespace std; inline int read() {
int x = , f = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') f = -; ch = getchar(); }
while (ch >= '' && ch <= '') { x = x * + ch - ; ch = getchar(); }
return x * f;
} const int N = 2e5 + ;
const int RT = ;
const int INF = 0x3f3f3f3f;
vector<int> group[N];
vector<int> rem[N];
vector<int> big;
vector<int> adj[N];
vector<int> dis[N];
int fa[N], lca[N][], n, dep[N], q, col[N]; void recalc(int c) {
if (dis[c].empty()) big.emplace_back(c);
dis[c].assign(n + , N);
queue<int> que;
for (int u: group[c]) {
dis[c][u] = ;
que.push(u);
}
while (!que.empty()) {
int u = que.front(); que.pop();
for (int v: adj[u]) {
if (dis[c][v] == N) {
dis[c][v] = dis[c][u] + ;
que.push(v);
}
}
}
rem[c].clear();
} void add(int u, int c) {
n++;
col[n] = c;
lca[n][] = fa[n] = u;
adj[n].emplace_back(u);
adj[u].emplace_back(n);
dep[n] = dep[u] + ;
for (int i = ; i <= ; i++) lca[n][i] = lca[lca[n][i-]][i-];
for (int cc: big) dis[cc].emplace_back(dis[cc][u] + );
group[c].emplace_back(n);
rem[c].emplace_back(n);
if (rem[c].size() >= RT) recalc(c);
} int Lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
int f = dep[u] - dep[v];
for (int i = ; i <= ; i++) {
if (f & ( << i)) {
u = lca[u][i];
}
}
if (u == v) return v;
for (int i = ; i >= ; i--) {
if (lca[u][i] != lca[v][i]) {
u = lca[u][i];
v = lca[v][i];
}
}
return lca[u][];
} int distance(int u, int v) {
return dep[u] + dep[v] - * dep[Lca(u, v)];
} int query(int u, int c) {
int ans = dis[c].size() ? dis[c][u] : N;
for (int v: rem[c]) ans = min(ans, distance(u, v));
if (ans == N) ans = -;
return ans;
} void init() {
for (int i = ; i < N; i++) {
adj[i].clear();
group[i].clear();
dis[i].clear();
rem[i].clear();
}
big.clear();
n = ;
} int main() {
int T = read();
while (T--) {
init();
q = read();int c = read();
group[c].emplace_back();
rem[c].emplace_back();
dep[] = ; fa[] = ;
int a = -;
while (q--) {
char s[];
scanf("%s", s);
int u = read(); c = read();
u = u ^ (a + ); c = c ^ (a + );
if (s[] == '+') add(u, c);
else printf("%d\n", a = query(u, c));
}
}
return ;
}
还是太菜了呀...
May Cook-Off 2019 解题报告的更多相关文章
- 【LeetCode】236. Lowest Common Ancestor of a Binary Tree 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 【LeetCode】684. Redundant Connection 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 并查集 日期 题目地址:https://leetco ...
- 【LeetCode】817. Linked List Components 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 【LeetCode】90. Subsets II 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 回溯法 日期 题目地址:https://leet ...
- CH Round #56 - 国庆节欢乐赛解题报告
最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...
- 二模13day1解题报告
二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...
- BZOJ 1051 最受欢迎的牛 解题报告
题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4438 Solved: 2353[S ...
- 习题:codevs 2822 爱在心中 解题报告
这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...
- 习题:codevs 1035 火车停留解题报告
本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...
随机推荐
- Win10最详细的优化设置 完美解决磁盘100%占用
1.用360优化win10后开不了机的问题原因是禁用了三个服务:在360应用软件服务里dmwappushsvc.diagnsticsTrackingservice.coreMessaging这三个要开 ...
- pytest_用例a失败,跳过测试用例b和c并标记失败xfail
前言 当用例a失败的时候,如果用例b和用例c都是依赖于第一个用例的结果,那可以直接跳过用例b和c的测试,直接给他标记失败xfail用到的场景,登录是第一个用例,登录之后的操作b是第二个用例,登录之后操 ...
- git 学习笔记 --从远程库克隆
上次我们讲了先有本地库,后有远程库的时候,如何关联远程库. 现在,假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆. 首先,登陆GitHub,创建一个新的仓库,名字叫gitskill ...
- Spark数据倾斜解决方案及shuffle原理
数据倾斜调优与shuffle调优 数据倾斜发生时的现象 1)个别task的执行速度明显慢于绝大多数task(常见情况) 2)spark作业突然报OOM异常(少见情况) 数据倾斜发生的原理 在进行shu ...
- Bootstrap中的datetimepicker用法总结
bootstrap时间控件参考文档(少走弯路) https://blog.csdn.net/hizzyzzh/article/details/51212867#31-format-%E6%A0%BC% ...
- 在部署 C#项目时转换 App.config 配置文件
问题 部署项目时,常常需要根据不同的环境使用不同的配置文件.例如,在部署网站时可能希望禁用调试选项,并更改连接字符串以使其指向不同的数据库.在创建 Web 项目时,Visual Studio 自动生成 ...
- form表单的密码是否一致校验功能
这是form类表单,自定义的form表单,需要重写钩子函数 """ forms类表单 """ # 校验密码是否一致 from django. ...
- html5的基本介绍
前言 (1)什么是HTML? 指超文本标记语言(Hyper Text Markup Language); 是用来描述网页的一种语言: 不是编程语言,是一种标记语言: (更多详细内容,百度:https: ...
- ORACLE ASMLIB
ORACLE ASMLIB This blog post is more of a note for myself on configuring ASMLib. ASMLib is an opti ...
- Linux应用与端口
lsof -i:port --- 得到对应端口的应用pid PS -ef|grep pid --- 根据pid得到对应应用