传送门

\(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题解的更多相关文章

  1. AtCoder Grand Contest 014 题解

    A - Cookie Exchanges 模拟 Problem Statement Takahashi, Aoki and Snuke love cookies. They have A, B and ...

  2. AtCoder Grand Contest 014

    AtCoder Grand Contest 014 A - Cookie Exchanges 有三个人,分别有\(A,B,C\)块饼干,每次每个人都会把自己的饼干分成相等的两份然后给其他两个人.当其中 ...

  3. AtCoder Grand Contest 014 D:Black and White Tree

    题目传送门:https://agc014.contest.atcoder.jp/tasks/agc014_d 题目翻译 给你一棵树,每次任选一个点染色,先手染白色,后手染黑色.如果最后存在一个白色的点 ...

  4. AtCoder Grand Contest 014 E:Blue and Red Tree

    题目传送门:https://agc014.contest.atcoder.jp/tasks/agc014_e 题目翻译 有一棵有\(N\)个点的树,初始时每条边都是蓝色的,每次你可以选择一条由蓝色边构 ...

  5. AtCoder Grand Contest 017 题解

    A - Biscuits 题目: 给出 \(n\) 个物品,每个物品有一个权值. 问有多少种选取方式使得物品权值之和 \(\bmod\space 2\) 为 \(p\). \(n \leq 50\) ...

  6. Atcoder Grand Contest 054 题解

    那天晚上由于毕业晚会与同学吃饭喝酒没打 AGC,第二天稍微补了下题,目前补到了 E,显然 AGC 的 F 对于我来说都是不可做题就没补了(bushi A 简单题,不难发现如果我们通过三次及以上的操作将 ...

  7. AtCoder Grand Contest 030题解

    第一次套刷AtCoder 体验良好 传送门 Poisonous Cookies cout<<b+min(c,a+b+); Tree Burning 难度跨度有点大啊 可以证明当第一次转向之 ...

  8. AtCoder Grand Contest 031题解

    题面 传送门 题解 比赛的之后做完\(AB\)就开始发呆了--简直菜的一笔啊-- \(A - Colorful\ Subsequence\) 如果第\(i\)个字母选,那么它前面任意一个别的字母的选择 ...

  9. AtCoder Grand Contest 039 题解

    传送门 \(A\) 首先只有一串的情况下,遇到相同的肯定是改后面那一个最优,然后两串的话可能要分奇偶讨论一下 //quming #include<bits/stdc++.h> #defin ...

随机推荐

  1. CF627E Orchestra [矩阵计数]

    也许更好的阅读体验 \(\mathcal{Description}\) 题目大意 有一个\(r * c\)的矩阵上有\(n\)个点,问有多少个子矩阵里包含至少\(k\)个点 输入格式 第一行四个数\( ...

  2. Spring核心概念学习笔记

    1.Spring主要用到两种设计模式 1.1 工厂模式 Spring容器就是实例化和管理全部Bean的工厂. 工厂模式可以将Java对象的调用者从被调用者的实现逻辑中分离出来. 调用者只关心被调用者必 ...

  3. docker 执行 docker system prune 导致Azure Devops build镜像失败

    运行docker的centos上, 只分配了16G的空间, 装了个mysql, 还有个rancher, 就只剩下2G的空间了, Azure Devops build镜像就出错了, 显示存储空间不足, ...

  4. WCF NetTcpBinding

    服务端: <system.serviceModel> <bindings> <netTcpBinding> <binding portSharingEnabl ...

  5. 让table中的td不会被过长的文字撑开,并且自动出现省略号

    <style type="text/css"> table {width:600px;table-layout:fixed;} td {white-space:nowr ...

  6. Jenkins多环境持续集成架构实践

    自动化部署主要是为了解决项目多.环境多.持续集成慢.部署操作麻烦.手动操作易出错.自动化运维等问题. Jenkins是开源CI&CD软件领导者, 提供超过1000个插件来支持构建.部署.自动化 ...

  7. HTML5新增元素和移除的元素?

    新增元素: 图像Canvas 多媒体video.audio 本地存储localStorage.sessionStorage 语义化更好的内容元素aticle.header.footer.nav.sec ...

  8. Ubuntu-18.04 LTS UEFI 安装U盘制作

    要把U盘作为UEFI启动盘,第一个分区要为FAT32分区,EFI程序放在/EFI/Boot/bootx64.efi.为了制作Ubuntu-18.04 LTS安装U盘,可以把一个U盘格式化为FAT32格 ...

  9. MFC_选择目录对话框_选择文件对话框_指定目录遍历文件

    选择目录对话框 void C资源共享吧视频广告清理工具Dlg::OnBnClickedCls() { // 清空编辑框内容 m_Edit.SetWindowTextW(L""); ...

  10. FreeRTOS优先级翻转

    举例 //高优先级任务的任务函数 void high_task(void *pvParameters) { while(1) { vTaskDelay(500); //延时500ms,也就是500个时 ...