AtCoder Grand Contest 014

A - Cookie Exchanges

有三个人,分别有\(A,B,C\)块饼干,每次每个人都会把自己的饼干分成相等的两份然后给其他两个人。当其中有一个人的饼干数量是奇数的时候停止,求会进行几次这样子的操作,或者会永远进行下去。

首先无解的情况一定是三个数都是相等的偶数。

否则直接暴力模拟就行了。(盲猜答案不会很大)

证明一下答案的范围:不妨令\(A\le B\le C\),那么最大值和最小值之间的差就是\(C-A\),那么执行完一次操作之后最大值和最小值的差变成了\(\frac{C-A}{2}\),这样子以来就可以证明执行次数不会超过\(log\)次了。

#include<iostream>
#include<cstdio>
using namespace std;
int a,b,c,ans;
int main()
{
scanf("%d%d%d",&a,&b,&c);
if(a%2==0&&a==b&&b==c){puts("-1");return 0;}
while(a%2==0&&b%2==0&&c%2==0)
{
int aa=a>>1,bb=b>>1,cc=c>>1;
a=bb+cc;b=aa+cc;c=aa+bb;++ans;
}
printf("%d\n",ans);
return 0;
}

B - Unplanned Queries

有一棵树,一开始所有边权都是\(0\),执行\(M\)次操作,每次会把\(a_i\)到\(b_i\)路径上的每一条边的边权全部加\(1\),切最终每一条边的边权都是偶数。判断这样一棵树是否存在。

对于所有操作随便构建一棵生成树出来进行一下判断就行了。

这样对的原因是因为你随便怎么连对于奇偶性是不改变的。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define MAX 100100
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,m,f[MAX],a[MAX];
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
vector<int> E[MAX];
void dfs(int u,int ff){for(int v:E[u])if(v!=ff)dfs(v,u),a[u]^=a[v];}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)f[i]=i;
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
if(getf(u)!=getf(v))
E[u].push_back(v),E[v].push_back(u),f[getf(u)]=getf(v);
a[u]^=1;a[v]^=1;
}
for(int i=1;i<=n;++i)
if(getf(i)!=getf(1))E[1].push_back(i),E[i].push_back(1),f[getf(i)]=getf(1); dfs(1,0);
for(int i=1;i<=n;++i)if(a[i]){puts("NO");return 0;}
puts("YES");
return 0;
}

C - Closed Rooms

有一个\(H\times W\)的网格,有些格子不能走。现在有一个人从某个起点开始,进行以下步骤:首先沿着相邻格子走不超过\(k\)步,然后选择不超过\(k\)个不能走的格子让它们变成能走。

问最少进行上述操作多少次这个人可以走到网格图的边界位置。

把操作顺序换一下,我们先走\(k\)次。接下来进行若干轮,每次都是先把\(k\)个格子解锁再走,等价于没有限制了。

所以只需要预处理先走\(k\)步可以到达的位置再计算一下最短路就行啦。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
#define MAX 808
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int ans,n,m,K,sx,sy;
char g[MAX][MAX];
int Calc(int x,int y){return min(min(x-1,n-x),min(y-1,m-y));}
int dis[MAX][MAX];
int d[4][2]={1,0,0,1,-1,0,0,-1};
void BFS(int sx,int sy)
{
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)dis[i][j]=1e9;
dis[sx][sy]=0;ans=1e9;
queue<int> Qx,Qy;Qx.push(sx),Qy.push(sy);
while(!Qx.empty())
{
int x=Qx.front(),y=Qy.front();Qx.pop();Qy.pop();
ans=min(ans,(Calc(x,y)+K-1)/K);
if(dis[x][y]>=K)continue;
for(int i=0;i<4;++i)
{
int xx=x+d[i][0],yy=y+d[i][1];
if(xx<1||xx>n||yy<1||yy>m)continue;
if(g[xx][yy]=='#')continue;
if(dis[xx][yy]<=dis[x][y]+1)continue;
dis[xx][yy]=dis[x][y]+1;
Qx.push(xx);Qy.push(yy);
}
}
}
int main()
{
n=read();m=read();K=read();
for(int i=1;i<=n;++i)scanf("%s",g[i]+1);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(g[i][j]=='S')sx=i,sy=j;
BFS(sx,sy);
printf("%d\n",ans+1);
return 0;
}

D - Black and White Tree

有一棵树,两个人轮流给节点染色,先手染白,后手染黑。

染完之后把所有和黑色节点相邻的点全部染黑。

如果还有白点则先手胜,否则后手胜。

判断胜负情况。

首先发现胜利情况是存在一个白点使得其相邻的点全是白点。

那么,发现如果这棵树存在一个完美匹配的话,那么后手必胜,即先手无论走哪个位置,后手一定可以走一个匹配的相邻的位置。

否则的话找一个不在匹配内的点作为根节点,这样子它的所有儿子的匹配都在其自身的子树内,这样子直接对于所有儿子染色,此时后手必须染其儿子对应的匹配,此时先手必胜。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define MAX 100100
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n;
vector<int> E[MAX];
bool dfs(int u,int ff)
{
int cnt=0;
for(int v:E[u])
{
if(v==ff)continue;
if(dfs(v,u))++cnt;
}
if(cnt>=2){puts("First");exit(0);}
return cnt^1;
}
int main()
{
n=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();
E[u].push_back(v);
E[v].push_back(u);
}
if(dfs(1,0))puts("First");
else puts("Second");
return 0;
}

E - Blue and Red Tree

你有一棵树,一开始所有边都是蓝色的。

你要执行\(n-1\)次如下的操作:每次选定一条全是蓝色边的路径,随意断掉其中一条边,然后在两个端点之间连上一条红边。

现在给你由红边组成的树,问你能否从蓝边树变成给定的红边树。

发现最后一次操作的边一定既在蓝树中又在红树中出现,而连完边之后这两个点就可以直接合并在一起。

那么我们每次找到这样一条边,然后把两个集合合并。

那么直接启发式合并处理这个问题就行了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define MAX 100100
#define pi pair<int,int>
#define mp make_pair
#define fr first
#define sd second
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,f[MAX];
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
queue<pi> Q;
map<pi,int> M;
set<int> E[MAX];
pi get(int x,int y){if(x>y)swap(x,y);return mp(x,y);}
void Link(int x,int y)
{
E[x].insert(y);E[y].insert(x);
pi u=get(x,y);
if(++M[u]==2)Q.push(u);
}
int main()
{
n=read();
for(int i=1;i<=n;++i)f[i]=i;
for(int i=1;i<=n+n-2;++i)Link(read(),read());
for(int i=1,x,y;i<n;++i)
{
do
{
if(Q.empty()){puts("NO");return 0;}
x=Q.front().fr,y=Q.front().sd;Q.pop();
x=getf(x);y=getf(y);
}while(x==y);
if(E[x].size()>E[y].size())swap(x,y);
f[x]=y;M.erase(get(x,y));E[y].erase(x);
for(auto v:E[x])
{
int fv=getf(v);
if(fv==y)continue;
M.erase(get(x,fv));
E[fv].erase(x);
Link(fv,y);
}
}
puts("YES");
return 0;
}

F - Strange Sorting

给定一个排列,把所有是前缀最大值的数直接丢到数列的最后,问多少次这样的操作之后数列会被排好序。

不会.jpg。所以可以开心的照抄___的题解了

首先发现\(1\)这个东西很有意思,它并不影响其他元素,即如果\(1\)在开头位置那么就没它的事了,否则它一定不会成为前缀最大值。那么我们把\(1\)给丢掉,只考虑\([2,n]\)的数量,假装它的答案是\(T\),那么最终的答案就是\(T\)或者\(T+1\)。首先\(T=0\)的情况特殊处理掉。否则的话考虑进行完\(T-1\)次之后的数列,设\(f\)为数列的第一项,那么\(f>2\),因为如果\(f=2\)的话证明这个序列要么已经排好序了,要么在下一次操作之后\(2\)会被丢到后面,又因为没有排好序,所以肯定不能只进行一次就得到最终序列。

这样子的话,进行完下一次操作之后\([2,n]\)就完成了排序,考虑把\(1\)给加入进来,如果数列前三项是\(f,1,2\),那么显然一次操作之后\(1\)也顺带回到了自己的位置,此时答案仍然是\(T\)。否则的话,一次操作之后显然\(1\)还没有归位,需要再进行一次\(1\)才能回到自己的位置上,此时答案是\(T+1\)。

然后我就不会证了,抄遍代码就滚粗了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 200200
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,a[MAX],b[MAX],T[MAX],f[MAX];
int main()
{
n=read();
for(int i=1;i<=n;++i)b[a[i]=read()]=i;
for(int i=n-1;i;--i)
if(!T[i+1])
{
if(b[i]>b[i+1])T[i]=1,f[i]=i+1;
else T[i]=0;
}
else
{
if((b[f[i+1]]<b[i])+(b[i]<b[i+1])+(b[i+1]<b[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;
}

最新文章

  1. CLR中的程序集加载
  2. [转]js来弹出窗口的详细说明
  3. iOS局部刷新
  4. 【python】python程序分行写符号
  5. BZOJ 3676 回文串
  6. 用jquery向网页添加背景图片 拉伸 模糊 遮罩层 代码
  7. iOS开发之圆角指定
  8. duilib消息类型
  9. windows 10下通过python3.6成功搭建jupyter 服务器
  10. 准备学习wrf
  11. ELK的sentinl告警配置详解
  12. babel 编译后 this 变成了 undefined
  13. ios nil、NULL和NSNull 的使用
  14. java.lang.IndexOutOfBoundsException: setSpan (35 ... 35) ends beyond length 28
  15. 分布式架构核心RPC原理
  16. 查看分析器(Analyzer)的分词效果
  17. Ecliplse导入maven项目applicationContext.xml报错:Referenced file contains errors (http://www.springframework.org/schema/context/spring-context-3.1.xsd). For more information, right click on the message in
  18. 242. Valid Anagram Add to List
  19. bzoj 3028 食物 —— 生成函数
  20. thinkphp不能够将ueditor中的html文本显示

热门文章

  1. oracle dg状态检查及相关命令
  2. [linux] 进程五状态模型
  3. 使用阿里云生成的pem密钥登录
  4. 详解MongDB数据库
  5. 如何在docker镜像里安装pycuda和numba?
  6. opencv使用cv::Mat_和push_back
  7. 每天一道Rust-LeetCode(2019-06-10)
  8. .NET中线程同步的几种方法
  9. 【未完成】【Mybatis】字段由字符+数字变量组成,但要对变量进行计算
  10. 8.11 NOIP模拟测试17 入阵曲+将军令+星空