AtCoder Grand Contest 014题解
\(A\)
首先大力猜测一下答案不会很大,所以次数大于\(10^6\)输出\(-1\)就行了
不过我并不会证上界,据说是因为如果\(a=b=c\)且都是偶数肯定\(-1\),否则设\(a\leq b\leq c\),则最大最小值的差为\(c-a\),一次操作之后变成了\({c-a\over 2}\),所以操作次数就是\(\log\)级别的了
typedef long long ll;
ll a,b,c,sum;int res;
int main(){
scanf("%lld%lld%lld",&a,&b,&c);
sum=a+b+c;
while(true){
if((a&1)|(b&1)|(c&1))return printf("%d\n",res),0;
a=(sum-a)>>1,b=(sum-b)>>1,c=(sum-c)>>1;
if(++res>1e6)return puts("-1"),0;
}
return 0;
}
\(B\)
既然题目要求每条边被覆盖偶数次,那么一定可以被拆分成若干个联通边集且这个边集里每条边都被覆盖\(2\)次,而这个边集肯定形如若干条\((a_1,a_2),(a_2,a_3),...,(a_n,a_1)\)的路径的并,再转化一下就是在新图中将\((u,v)\)连边,且新图可以被拆分成若干条欧拉回路。那么充要条件就是每个点度数都为偶数
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2e5+5;
int d[N],n,m;
int main(){
scanf("%d%d",&n,&m);
for(R int i=1,u,v;i<=m;++i)scanf("%d%d",&u,&v),++d[u],++d[v];
fp(i,1,n)if(d[i]&1)return puts("NO"),0;
puts("YES");
return 0;
}
\(C\)
肯定是先随便走到一个点,然后消走消走的就可以直接往一个方向冲了,那么\(bfs\)找出所有一开始能到的点,然后看看从哪个点开始冲就是了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1005;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
char mp[N][N];int vis[N][N],dis[N][N],qx[N*N],qy[N*N],n,m,k,res,sx,sy;
inline int calc(R int x,R int y){
cmin(res,(x-1+k-1)/k),cmin(res,(n-x+k-1)/k);
cmin(res,(y-1+k-1)/k),cmin(res,(m-y+k-1)/k);
}
void bfs(){
int h=1,t=0,x,y,tx,ty;qx[++t]=sx,qy[t]=sy,vis[sx][sy]=1,dis[sx][sy]=0;
while(h<=t){
x=qx[h],y=qy[h++];
if(dis[x][y]==k)continue;
fp(i,0,3){
tx=x+dx[i],ty=y+dy[i];
if(!vis[tx][ty]&&tx>=1&&tx<=n&&ty>=1&&ty<=m)
++t,qx[t]=tx,qy[t]=ty,vis[tx][ty]=1,dis[tx][ty]=dis[x][y]+1;
}
}
fp(i,1,t)calc(qx[i],qy[i]);
}
int main(){
scanf("%d%d%d",&n,&m,&k),res=2333333;
fp(i,1,n){
scanf("%s",mp[i]+1);
fp(j,1,m){
if(mp[i][j]=='S')sx=i,sy=j;
if(mp[i][j]=='#')vis[i][j]=1;
}
}
bfs();
printf("%d\n",res+1);
return 0;
}
\(D\)
显然曲明最擅长的就是猜测出假的结论
首先给出结论:后手必胜当且仅当这棵树有完美匹配
这棵树有完美匹配的时候,因为先手染什么颜色后手只要染它的匹配,就能保证每个白色节点有至少一个与它相邻的黑色节点了
如果一个点连着两个以上的叶子必定是先手必胜了,所以接下来我们默认所有的点连着的叶子个数小于等于\(1\)
如果没有完美匹配,我们随便找一个点为根,然后对于一个叶子,先手把它的父亲染白,那么后手必须把这个叶子染黑。然后我们把这两个点从树中删去,继续操作。显然树不会被删完,否则就存在完美匹配了。此时我们随便染白一个还未染的点就赢了
于是充要性都有了
求完美匹配直接从叶子开始贪心就是
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2e5+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int dep[N],vis[N],fa[N],n;
void dfs(int u,int fa){
go(u)if(v!=fa)dfs(v,u);
if(!vis[u]&&vis[fa]){puts("First");exit(0);}
if(!vis[u])vis[u]=vis[fa]=1;
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d",&n);
for(R int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),add(u,v),add(v,u);
vis[0]=1;dfs(1,0);
puts("Second");
return 0;
}
\(E\)
容易发现,一次操作合法,当且仅当删掉蓝边和删掉红边之后两边点集是一样的
那么我们考虑倒着加边,则如果两个连通块之间多于\(1\)条边,那么必定是一条红边一条蓝边,且这个操作可以进行,那么我们把这两个连通块缩成一个点就好了
关于维护连通块直接的边集,可以用\(multiset\),然后启发式合并就行了
//quming
#include<bits/stdc++.h>
#define R register
#define fi first
#define se second
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef pair<int,int> pi;
const int N=2e5+5;
multiset<int>to[N];map<pi,int>mp;queue<pi>q;int n;
inline void ins(R int u,R int v){
if(u==v)return;
if(u>v)swap(u,v);
++mp[pi(u,v)],to[u].insert(v),to[v].insert(u);
if(mp[pi(u,v)]==2)q.push(pi(u,v));
}
inline void del(R int u,R int v){
if(u>v)swap(u,v);
if(mp.count(pi(u,v)))mp.erase(pi(u,v));
}
inline void merge(R int u,R int v){
for(auto w:to[v])del(w,v),to[w].erase(to[w].find(v)),ins(w,u);
}
int main(){
scanf("%d",&n);
for(R int i=1,u,v;i<=n*2-2;++i)scanf("%d%d",&u,&v),ins(u,v);
fp(i,1,n-1){
while(233){
if(q.empty())return puts("NO"),0;
R pi t=q.front();q.pop();
if(mp.count(t)){
if(to[t.fi].size()<to[t.se].size())swap(t.fi,t.se);
merge(t.fi,t.se);
break;
}
}
}
puts("YES");
return 0;
}
\(F\)
好神仙的题啊……
这篇题解比起其他题解的优势是翻译的比较全
首先我们发现,如果去掉\(1\)是不会改变每个元素是\(low\)还是\(high\)的,那么我们去掉\(1\),假设需要\(T\)次令\(2\)到\(n\)有序,如果此时\(1\)已经在最前面了,那么答案就是\(T\),否则是\(T+1\)
如果\(T=0\),那么答案是\(T\)还是\(T+1\)很好判断。否则我们考虑进行了\(T-1\)次操作之后的序列,令\(f\)是\(2\)到\(n\)中排在最前面的元素,易知\(f>2\)(如果\(f=2\)的话,可以用反证法证明,要么此时\(2\)到\(n\)已经有序,要么再进行一次操作之后仍不有序)。然后我们发现,当且仅当此时三个数的相对位置形如\((f,1,2)\)时,答案为\(T\),否则为\(T+1\)
然后我们要证明这三个数在环上的相对位置是不变的,也就是说如果初始时相对位置为\((1,2,f)\),那么变化过程中相对位置只会有\((1,2,f),(2,f,1),(f,1,2)\)三种情况
先来证明另一件事,就是\(f\)如果不是在\(2\)到\(n\)中所有数的最前面,它必定是一个\(low\)元素。这一段中考虑的元素只有\(2\)到\(n\)。考虑反证法,假设\(x\)是一个不在第一位的\(high\)元素,因为第一位必定是\(high\),所以一次操作之后必定存在一个\(y\)使得\(y<x\)且\(y\)在\(x\)前面,接下来的操作过程中,如果\(y,x\)类型相同它们必定同时移动,而它们分开当且仅当某个时刻\(y\)是\(low\)而\(x\)是\(high\),不过因为此时\(x\)依然不是第一个元素,所以又陷入了之前那种情况。所以可以发现如果\(f\)是一个不在最前面的\(high\)元素它无论如何都不可能在\(T-1\)次操作后到达最前面,所以上面那个结论成立
然后开始分类讨论了
- 如果\(1\)在第一个
- 如果\(2\)在第二个,那么\(1,2\)是\(high\)而\(f\)是\(low\),环不会变
- 如果\(f\)是第二个,那么\(1,f\)是\(high\)而\(2\)是\(low\),环不会变
- 否则\(1\)是\(high\),\(2,f\)是\(low\),环不会变
- 如果\(2\)是第一个,那么\(2\)是\(high\)而\(1,f\)是\(low\),环不会变
- 如果\(f\)是第一个,那么\(f\)是\(high\)而\(1,2\)是\(low\),环不会变
- 否则\(1,2,f\)都是\(low\),环不会变
然后我们来倒推,设\(T_i\)表示只考虑\(i\)到\(n\)的元素时的最小次数,\(f_i\)表示此时对应的\(f\),如果\(T_i=0\)则\(f_i\)未定义。初值为\(T_1=0\),答案为\(T_1\)
我们设\(q_i\)表示\(i\)的位置,即\(p_{q_i}=i\),然后递推过程如下
- 如果\(T_{i+1}=0\)
- 如果\(q_i>q_{i+1}\),则\(T_i=1,f_i=i+1\)
- 否则\(T_i=0\)
- 否则
- 如果三个元素的环按照\(q_{f_{i+1}},q_i,q_{i+1}\)的顺序,则\(T_i=T_{i+1},f_i=f_{i+1}\)
- 否则\(T_i=T_{i+1}+1,f_i=i+1\)
时间复杂度\(O(n)\)
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2e5+5;
int p[N],q[N],f[N],t[N],n;
int main(){
scanf("%d",&n);
fp(i,1,n)scanf("%d",&p[i]),q[p[i]]=i;
t[n]=0;
fd(i,n-1,1)
if(!t[i+1])q[i]>q[i+1]?(t[i]=1,f[i]=i+1):t[i]=0;
else{
if((q[f[i+1]]<q[i])+(q[i]<q[i+1])+(q[i+1]<q[f[i+1]])==2)
t[i]=t[i+1],f[i]=f[i+1];
else t[i]=t[i+1]+1,f[i]=i+1;
}
printf("%d\n",t[1]);
return 0;
}
AtCoder Grand Contest 014题解的更多相关文章
- AtCoder Grand Contest 014 题解
A - Cookie Exchanges 模拟 Problem Statement Takahashi, Aoki and Snuke love cookies. They have A, B and ...
- AtCoder Grand Contest 014
AtCoder Grand Contest 014 A - Cookie Exchanges 有三个人,分别有\(A,B,C\)块饼干,每次每个人都会把自己的饼干分成相等的两份然后给其他两个人.当其中 ...
- AtCoder Grand Contest 014 D:Black and White Tree
题目传送门:https://agc014.contest.atcoder.jp/tasks/agc014_d 题目翻译 给你一棵树,每次任选一个点染色,先手染白色,后手染黑色.如果最后存在一个白色的点 ...
- AtCoder Grand Contest 014 E:Blue and Red Tree
题目传送门:https://agc014.contest.atcoder.jp/tasks/agc014_e 题目翻译 有一棵有\(N\)个点的树,初始时每条边都是蓝色的,每次你可以选择一条由蓝色边构 ...
- AtCoder Grand Contest 017 题解
A - Biscuits 题目: 给出 \(n\) 个物品,每个物品有一个权值. 问有多少种选取方式使得物品权值之和 \(\bmod\space 2\) 为 \(p\). \(n \leq 50\) ...
- Atcoder Grand Contest 054 题解
那天晚上由于毕业晚会与同学吃饭喝酒没打 AGC,第二天稍微补了下题,目前补到了 E,显然 AGC 的 F 对于我来说都是不可做题就没补了(bushi A 简单题,不难发现如果我们通过三次及以上的操作将 ...
- AtCoder Grand Contest 030题解
第一次套刷AtCoder 体验良好 传送门 Poisonous Cookies cout<<b+min(c,a+b+); Tree Burning 难度跨度有点大啊 可以证明当第一次转向之 ...
- AtCoder Grand Contest 031题解
题面 传送门 题解 比赛的之后做完\(AB\)就开始发呆了--简直菜的一笔啊-- \(A - Colorful\ Subsequence\) 如果第\(i\)个字母选,那么它前面任意一个别的字母的选择 ...
- AtCoder Grand Contest 039 题解
传送门 \(A\) 首先只有一串的情况下,遇到相同的肯定是改后面那一个最优,然后两串的话可能要分奇偶讨论一下 //quming #include<bits/stdc++.h> #defin ...
随机推荐
- Oracle.EntityFrameworkCore使用时报错:ORA-00933:SQL命令未正确结束
如果你在使用 Oracle.EntityFrameworkCore 在执行一些分页查询或者其他数据操作时,遇到“ORA-00933:SQL命令未正确结束”, 请先检查你的DbContext中UseOr ...
- linux route详细解读
route命令用于显示和操作IP路由表.要实现两个不同的子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现.在Linux系统中,设置路由通常是 为了解决以下问题:该Linu ...
- 匿名对象序列化为XML
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.X ...
- springboot activiti 工作流版本 集成代码生成器 shiro 安全框架
官网:www.fhadmin.org 工作流模块---------------------------------------------------------------------------- ...
- iOS - WWDC18 iOS 自动生成强密码和自动填充验证码/密码
本文将介绍WWDC18 Automatic Strong Passwords and Security Code Autofill和WWDC17 Introducing Password AutoFi ...
- ios开发之NSData
NSData用于保存字节数组. 初始化 - (instancetype)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length free ...
- python两则99乘法表
分别应用while和for的嵌套循环,适用于初学的人看看 x = 1 while x <= 9: y = 1 while y <= x: print (y,'*',x,'=',x*y,en ...
- mysql学习之基础篇08 UTF8编码
这次我们来说一下在Mysql中的编码问题: 我们知道应用于计算机的最早的字符集是ASCII,它所组成的编码是ASCII编码:由于对于其他国家来说它所容纳的字符个数比较少,后来就出现了ANSI字符集,它 ...
- Java Decompiler反编译Jar文件
1.重新编译已经打包的Jar包,使用 Java Decompiler 打开需要重新编译的jar包,找到自己需要自己修改的Class文件 ,修改之后电子保存文件 ,保存的时候编译工具自动将class文件 ...
- Go数据类型之复合数据类型--数组
3.1数组 数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成.数组中每个元素类型相同,又是连续分配,因此可以以固定的速度索引数组中的任何数据,速度非常快. 3.1.1声明 ...