AtCoder Grand Contest 014做题记录
来源:互联网 发布:mysql修改root密码 编辑:程序博客网 时间:2024/06/07 19:39
这场AtCoder的题目以结论题为主
代码都很短,想法也都很巧妙
A - Cookie Exchanges
按照题目描述暴力即可
关键在于时间复杂度的证明
对于三个数
不妨令减去
对这三个数两两做差求和,变化前的和为
#include <bits/stdc++.h>using namespace std;int main() { int a,b,c,ans = 0; cin >> a >> b >> c; for (;;) { if ((a&1) || (b&1) || (c&1)) { printf("%d\n",ans); break; } if (a == b && b == c) { puts("-1"); break; } ans++; int na = (b + c) >> 1; int nb = (a + c) >> 1; int nc = (a + b) >> 1; a = na, b = nb, c = nc; } return 0;}
B - Unplanned Queries
原问题相当于对树上一条路径的边异或1
注意到是树边而不是点,单次操作(a,b)可以分解为(rt,a),(rt,b)两个操作,rt为树根,这两次异或操作对LCA(a,b)以上的的边的影响可以抵消。
结论:存在一棵符合题意的树当且仅当所有形如(rt,x)的操作中,每个x出现的次数都为偶数
充分性:所有的操作都做了偶数次,第
必要性:若存在一种合法的方案,对某个点进行了奇数次操作并且存在一棵合法的树,取所有的被操作了奇数次点中深度最大的点,它的子树中除了它所有的点都被操作了偶数次,而该点被操作了奇数次,那么改点和它父亲的连边被操作了奇数次,矛盾。
最终解法只需要
#include <bits/stdc++.h>#define N 1000500using namespace std;inline int rd() {int r;scanf("%d",&r);return r;}int n,m,d[N];int main() { n = rd(), m = rd(); for (int i=1;i<=m;i++) d[rd()]++, d[rd()]++; int ans = 1; for (int i=1;i<=n;i++) if (d[i]&1) ans = 0; puts(ans?"YES":"NO"); return 0;}
C - Closed Rooms
操作相当于先移动K步,然后每次开K个门移动K步
先爆搜出从起点移动K步能到达的所有的点,这一步可以在
后面每次允许开K个门并且移动K步,相当于移动不受地形限制,朝四条边中距离它最近的一条边直线行走一定是最优的方案。对于一开始能移动到的没一个点都判断一次,同样这一步能够在
总时间是
#include <bits/stdc++.h>#define N 1805using namespace std;const int fx[] = { 0, 1, 0,-1};const int fy[] = { 1, 0,-1, 0};int n,m,k,sx,sy;char s[N];bool vis[N][N],mp[N][N],flag;queue<int> qx,qy,qs;int main() { scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=n;i++) { scanf("%s",s+1); for (int j=1;j<=m;j++) mp[i][j] = s[j]!='#'; for (int j=1;j<=m;j++) if (s[j]=='S') sx=i, sy=j; } if (sx == 1 || sx == n || sy == 1 || sy == m) return puts("0"), 0; vis[sx][sy] = 1; qx.push(sx), qy.push(sy), qs.push(0); while (!qx.empty()) { int ux = qx.front(); qx.pop(); int uy = qy.front(); qy.pop(); int us = qs.front(); qs.pop(); if (us == k) continue; if (ux == 1 || ux == n || uy == 1 || uy == m) flag = 1; for (int i=0;i<4;i++) { int vx = ux + fx[i], vy = uy + fy[i]; if (vx<1 || vx>n || vy<1 || vy>m) continue; if (!vis[vx][vy] && mp[vx][vy]) { vis[vx][vy] = 1; qx.push(vx), qy.push(vy), qs.push(us+1); } } } if (flag) return puts("1"), 0; int ans = 2147483647; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (vis[i][j]) { int t = min( min(i-1,j-1) , min(n-i,m-j) ); int cur = (t+k-1) / k; ans = min(ans, cur+1); } cout << ans << endl; return 0;}
D - Black and White Tree
结论:后手必胜当且仅当树存在完备匹配
充分性:对于先手每一次操作染色的点
必要性:先手每次找到最深的一个未染色点
若
若
复杂度取决于判断树是否存在完备匹配,用从叶子结点贪心的方法可以做到
#include <bits/stdc++.h>#define N 1000500using namespace std;inline int rd() {int r;scanf("%d",&r);return r;}vector<int> e[N];int p[N],n;void link(int a,int b) {e[a].push_back(b), e[b].push_back(a);}void dfs(int u,int f) { for (int i=0;i<(int)e[u].size();i++) { int v=e[u][i]; if (v==f) continue; dfs(v,u); } if (!p[u] && !p[f]) p[u] = p[f] = 1; }int main() { n = rd(); for (int i=1;i<n;i++) link(rd(),rd()); p[0] = 1; dfs(1,0); int ans = 1; for (int i=1;i<=n;i++) if (!p[i]) ans = 0; puts(!ans?"First":"Second"); return 0;}
E - Blue and Red Tree
若将一条蓝边删去,原来的树将被划分成两个连通块,新连的红边又将连接这两个连通块,并且这条红边是唯一连接这两个连通块的边。
每次选择两个连通块,满足这两个连通块间有且仅有一条蓝边和红边,连接这两个连通块。
用队列维护需要被处理的两个连通块,map维护连通块之间的边数,vector存边。启发式合并这些信息。
启发式合并一个log,map一个log
时间复杂度
#include <bits/stdc++.h>#define x first#define y second#define N 100050using namespace std;typedef pair<int,int> pii;map<pii,int> mp;vector<int> e[N];queue<pii> q;int fa[N],siz[N],tot,n;pii MP(int a,int b) {if (a>b) swap(a,b); return make_pair(a,b);}inline int rd() {int r;scanf("%d",&r);return r;}void link(int a,int b) { e[a].push_back(b); e[b].push_back(a); mp[MP(a,b)]++;}int gf(int u) {return fa[u]==u?u:gf(fa[u]);}int main() { n = rd(); for (int i=1;i<=n;i++) fa[i] = i; for (int i=1;i<=2*n-2;i++) link(rd(), rd()); for (map<pii,int>::iterator it=mp.begin();it!=mp.end();it++) if (it->y == 2) q.push(it->x); while (!q.empty()) { pii u = q.front(); q.pop(); int a = gf(u.x), b = gf(u.y); if (a == b) continue; ++tot; if (siz[a] < siz[b]) swap(a, b); for (int i=0;i<(int)e[b].size();i++) { int t=gf( e[b][i] ); if (t == a) continue; e[a].push_back(t); mp[ MP(b, t) ]--; mp[ MP(a, t) ]++; if (mp[ MP(a, t) ] == 2) q.push( MP(a, t) ); } e[b].clear(); fa[b] = a; } puts(tot==n-1?"YES":"NO"); return 0;}
F留坑待填
- AtCoder Grand Contest 014做题记录
- AtCoder Grand Contest 016做题记录
- AtCoder Grand Contest 017做题记录
- AtCoder Grand Contest 018 做题记录
- Atcoder Grand Contest 014F
- AtCoder Grand Contest 010
- AtCoder Grand Contest 011
- AtCoder Grand Contest 018
- AtCoder Grand Contest 018
- Atcoder Grand Contest 019
- AtCoder Grand Contest 010
- AtCoder Grand Contest 008
- Atcoder 刷题记录
- Atcoder Grand Contest 011E
- Atcoder Grand Contest 011F
- AtCoder Grand Contest 012 B
- AtCoder Grand Contest 012 A
- AtCoder Grand Contest 012 题解
- Android应用使用https
- 企业网站内部链接的形式分析
- UIBarButtonItem的一个分类,用户快速创建一个UIBarButtonItem
- 通过输入流的方式获取Request中的json参数
- 二叉树的镜像
- AtCoder Grand Contest 014做题记录
- 计蒜客_爬楼梯
- Inception 模型
- Maven项目下java.lang.ClassNotFoundException常规解决办法
- 回掉函数使用
- java反射--高级开发必须懂的
- Java 动态代理机制分析及扩展
- 1005. 继续(3n+1)猜想 (25) PAT
- SpringBoot笔记一