传送门

\(A\)

判一下奇数的个数就行了

const int N=1e5+5;
int a[N],n,res;
int main(){
scanf("%d",&n);
fp(i,1,n)scanf("%d",&a[i]),res^=(a[i]&1);
puts(res?"NO":"YES");
return 0;
}

\(B\)

首先记录一下所有数的总和\(sum\),然后判断一下加到这个\(sum\)需要进行几次操作

我们考虑能否把该序列变为\(0\),把序列给差分,即令\(b_i=a_i-a_{i-1},b_1=a_1-a_n\),那么发现一次操作之后会令所有\(b_i-=1\)以及某一个\(b_i+=n\)

我们最终的目的首先要让所有\(b_i\)变为\(0\),又因为所有\(b_i\)的和为\(0\)且一次操作之后总和不变,我们只要让所有\(b_i\)相等即可,而操作的时候只有\(+n\)这个操作会改变相对大小,那么判断一下所有数能否通过\(+n\)变为最大的数就好了

如果可以,那么记此时需要的操作次数为\(cnt\),如果满足\(sum\geq cnt\)并且\(sum-cnt\)是\(n\)的倍数就说明可行了

//quming
#include<bits/stdc++.h>
#define R register
#define int long long
#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=1e5+5;
int a[N],b[N],n,sum,res;
signed main(){
scanf("%lld",&n);
fp(i,1,n)scanf("%lld",&a[i]),sum+=a[i];
if(sum%(n*(n+1)>>1))return puts("NO"),0;
sum/=(n*(n+1)>>1);
fp(i,2,n)b[i]=a[i]-a[i-1];b[1]=a[1]-a[n];
sort(b+1,b+1+n);
fp(i,1,n-1)if((b[i+1]-b[i])%n)return puts("NO"),0;
fp(i,1,n-1)res+=(b[n]-b[i])/n;
if(sum<res||(sum-res)%n)return puts("NO"),0;
puts("YES");
return 0;
}

\(C\)

随便选一个不是叶子的点做根,那么对于一个不是叶子的点,经过它的路径必然有一端来自它的一棵子树。对于点\(u\),假设它的子树里会分别延伸出\(f_v\)条路径,记\(sum=\sum f_v\),\(cnt\)为相互连接了的路径条数,那么\(u\)被覆盖的次数就是\(sum-cnt\),而且剩下的\(sum-cnt*2\)条路径会继续往上延伸

那么我们记\(f_u\)表示使\(u\)以及子树内都满足条件,此时\(u\)需要往上延伸多少条路径,树形\(dp\)即可,记得最后判一下\(f_1\)是否为\(0\)

具体细节看代码

//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;
typedef long long ll;
const int N=1e5+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;}
ll f[N];int deg[N],a[N],rt,n;
void dfs(int u,int fa){
if(deg[u]==1)return f[u]=a[u],void();
R ll sum=0,mx=0;
go(u)if(v!=fa)dfs(v,u),cmax(mx,f[v]),sum+=f[v];
R ll cnt=((mx<<1)<=sum?sum>>1:sum-mx);
if(sum<a[u]||sum-a[u]>cnt){puts("NO");exit(0);}
f[u]=sum-((sum-a[u])<<1);
}
int main(){
scanf("%d",&n);
fp(i,1,n)scanf("%d",&a[i]);
for(R int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),add(u,v),add(v,u),++deg[u],++deg[v];
if(n==2)return puts(a[1]==a[2]?"YES":"NO"),0;
fp(i,1,n)if(deg[i]!=1){rt=i;break;}
dfs(rt,0);
puts(f[rt]?"NO":"YES");
return 0;
}

\(D\)

博弈日常不会做

这题的结论:如果有奇数个偶数则先手必胜

首先这里的所有数\(\gcd\)为\(1\),代表着所有数里至少有一个奇数(很重要的性质,然而并没有发现)

那么先手一开始先将一个偶数变为奇数,然后就可以搬把小凳子来等着赢了:

后手如果选择将一个奇数变为偶数,先手可以选择一个偶数使其变为奇数

先手如果选择将一个偶数变为奇数,先手可以选择另一个偶数使其变为奇数

那么无论何时偶数的个数都为偶数,且因为这个过程中序列中至少存在一个奇数,所以\(\gcd\)绝对不会是偶数,也就是说奇偶的个数不会改变

也就是说先手赢定了

那么后手只能等死了么?或者如果有偶数个偶数就先手必胜?

回来考虑有偶数个偶数的情况,如果奇数的个数大于\(1\),那么先手不管怎么操作都会导致都会变成上面那种局面导致后手必赢,不过如果此时奇数的个数为\(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=1e5+5;
int a[N],n;
bool solve(){
fp(i,1,n)if(a[i]&1){
if(a[i]==1)return 0;
--a[i];break;
}
R int d=0;
fp(i,1,n)d=__gcd(d,a[i]);
fp(i,1,n)a[i]/=d;
R int t=0,sz=0;
fp(i,1,n)t^=(a[i]&1^1),sz+=(a[i]&1);
if(t||sz!=1)return t^1;
return solve()^1;
}
int main(){
scanf("%d",&n);
fp(i,1,n)scanf("%d",&a[i]);
R int t=0,sz=0;
fp(i,1,n)t^=(a[i]&1^1),sz+=(a[i]&1);
if(t||sz!=1)return puts(t?"First":"Second"),0;
puts(solve()?"First":"Second");
return 0;
}

\(E\)

模型日常不会转化

首先我们假设\(A\)已经把序列重新排列好了,那么\(B\)要怎么做才能使得字典序最大

容易发现如果两个数不互质,那么这两个数的相对顺序是不变的,另一方面,如果新的序列和原来序列每两个不互质的数相对位置不变,证明这个新的序列合法

那么如果\(i<j\)且\(\gcd(a_i,a_j)\neq 1\),我们就从\(i\)向\(j\)连一条边,最后只要求这个图字典序最大的拓扑序就可以了。鉴于这个图有着如果\(a_i=a_j\)则\(i,j\)有相同的出边的优秀性质,所以我们可以直接贪心的跑出最大的字典序

然后来考虑\(A\)在这种情况下该怎么卡,先把之前连的边变成无向边,然后我们需要对所有边定向。首先各个连通块之间是独立的,因为对于两个连通块形成的序列,\(B\)一定可以把这两个序列合并成字典序最大的而不改变每个序列里的相对顺序。

所以考虑单独一个联通快该怎么卡,首先我们找到这个连通块中最小的点\(u\),并以\(u\)为根节点随便跑一棵生成树,那么我们发现这样的话这个连通块中\(B\)能选择的第一个点只能是\(u\)了。那么我们继续考虑\(A\)如何让之后的也尽量优,\(A\)可以删掉点\(u\),然后从小到大枚举它的每一个出点,并对每一个出点也执行这个过程。我们发现最后会形成一棵\(dfs\)生成树,而且这个\(dfs\)生成树就是最优的,那么其它边实际上并不会影响最终的序列了

然后没有然后了

//quming
#include<bits/stdc++.h>
#define R register
#define pb push_back
#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=2005+5,M=5e6+5;
struct eg{int v,nx;}e[M];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
vector<int>to[N];int deg[N],vis[N],a[N],n;
priority_queue<int>q;
void dfs(int u){
vis[u]=1;
for(auto v:to[u])if(!vis[v])add(u,v),++deg[v],dfs(v);
}
int main(){
scanf("%d",&n);
fp(i,1,n)scanf("%d",&a[i]);
sort(a+1,a+1+n);
fp(i,1,n)fp(j,i+1,n)if(__gcd(a[i],a[j])>1)to[i].pb(j),to[j].pb(i);
fp(i,1,n)if(!vis[i])dfs(i);
fp(i,1,n)if(!deg[i])q.push(i);
for(R int u;!q.empty();){
u=q.top(),q.pop();
printf("%d ",a[u]);
go(u)if(!--deg[v])q.push(v);
}
return 0;
}

\(F\)

我为什么总是想了一点点就停止了……明明再想下去就能出来了……

首先我们枚举初始时棋子放在那个点上,然后以这个点为根\(dfs\)

对于一个点,定义\(f_u\)表示游戏只在\(u\)的这个子树中(即棋子不会出去),且初始时棋子在\(u\),那么先手必胜还是必败

那么最后\(f_{rt}\)就是根节点的答案

先给出结论:

\(1.\)若存在点\(v\)满足\(a_u>a_v\)且\(v\)子树中先手必败,则\(u\)先手必胜

\(2.\)否则\(u\)先手必败(或者\(u\)是叶子)

先证明第一个,首先\(a_u>a_v\)证明\(a_u\neq 0\),那么肯定可以下去,而此时如果后手想从\(v\)回来,\(u\)可以又让它下去。因为\(a_u>a_v\),所以如果一直这么秦王绕柱走的话最后肯定先手必胜,所以\(v\)肯定不会回来了,也就是说接下来的游戏的确只在\(v\)的子树中。然而万一后手的目的是通过这样秦王绕柱走来减小\(a_v\)呢?我们发现及时\(a_v\)减小,\(v\)子树内的必败也不会变为必胜,所以并没有影响

关于第二个的证明,首先叶子不用说了,否则假设\(u\)到了\(v\),那么必有\(v\)子树必胜或者\(a_u\leq a_v\),如果是后者那么后手跟先手秦王绕柱走,先手必死。如果是前者后手按子树里的必胜策略走就是,还是必胜

那么直接\(O(n^2)\)就可以了

\(ps:\)鉴于题解里那一句挑(调)衅(戏)的话,顺便写了一下\(O(n)\)的,就是在\(O(n^2)\)的基础上加个换根就行了

这里是\(O(n^2)\)的

//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=5005;
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 f[N],a[N],n;
void dfs(int u,int fa){
f[u]=0;
go(u)if(v!=fa&&a[u]>a[v])dfs(v,u),f[u]|=f[v]^1;
}
int main(){
scanf("%d",&n);
fp(i,1,n)scanf("%d",&a[i]);
for(R int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),add(u,v),add(v,u);
fp(i,1,n)dfs(i,0);
fp(i,1,n)if(f[i])printf("%d ",i);
return 0;
}

这里是\(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=5005;
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 ans[N],f[N],a[N],sz[N],n;
void dfs1(int u,int fa){
f[u]=0;
go(u)if(v!=fa){
dfs1(v,u),++sz[u];
if(a[u]>a[v])f[u]|=!f[v];
}
}
void dfs2(int u,int fa,int pa){
pa=(a[u]>a[fa]&&!pa);
ans[u]=f[u]|pa;
vector<int>st(sz[u]+2),Pre(sz[u]+2),suf(sz[u]+2);
int top=0;
go(u)if(v!=fa)st[++top]=v;
Pre[0]=0;fp(i,1,top)Pre[i]=Pre[i-1]|(a[u]>a[st[i]]&&!f[st[i]]);
suf[top+1]=0;fd(i,top,1)suf[i]=suf[i+1]|(a[u]>a[st[i]]&&!f[st[i]]);
fp(i,1,top)dfs2(st[i],u,Pre[i-1]|suf[i+1]|pa);
}
int main(){
scanf("%d",&n);
fp(i,1,n)scanf("%d",&a[i]);
for(R int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),add(u,v),add(v,u);
dfs1(1,0),dfs2(1,0,1);
fp(i,1,n)if(ans[i])printf("%d ",i);
return 0;
}

AtCoder Grand Contest 010题解的更多相关文章

  1. AtCoder Grand Contest 010

    AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...

  2. Atcoder Grand Contest 010 C - Cleaning 树贪心(伪)

    C - Cleaning 题目连接: http://agc010.contest.atcoder.jp/tasks/agc010_c Description There is a tree with ...

  3. Atcoder Grand Contest 010 B - Boxes 差分

    B - Boxes 题目连接: http://agc010.contest.atcoder.jp/tasks/agc010_b Description There are N boxes arrang ...

  4. AtCoder Grand Contest 010 C:Cleaning

    题目传送门:https://agc010.contest.atcoder.jp/tasks/agc010_c 题目翻译 给你一棵树,每个点有个权值,每次操作可以选择两个度数为\(1\)的结点,然后让这 ...

  5. AtCoder Grand Contest 017 题解

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

  6. AtCoder Grand Contest 010 F - Tree Game

    题目传送门:https://agc010.contest.atcoder.jp/tasks/agc010_f 题目大意: 给定一棵树,每个节点上有\(a_i\)个石子,某个节点上有一个棋子,两人轮流操 ...

  7. Atcoder Grand Contest 054 题解

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

  8. AtCoder Grand Contest 030题解

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

  9. AtCoder Grand Contest 031题解

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

随机推荐

  1. java之struts2的ThreadLocal和ActionContext

    在之前的学习中,我们知道struts2可以将表单中的数据自动设置到处理类的属性上,还有类型转换等其他功能.那么struts2是怎样做这件事情的呢? struts2完成这些功能是通过拦截器来完成的,并且 ...

  2. 【洛谷 P4070】 [SDOI2016]生成魔咒(后缀自动机)

    题目链接 建出\(SAM\)后,不同子串个数就是\(\sum len(i)-len(fa(i))\) 因为\(SAM\)在线的,所以每加入一个字符就能直接加上其贡献,于是这道题就没了. 因为\(x\) ...

  3. Synchronized 和 Lock 的主要区别(转)

    Synchronized 和 Lock 的主要区别Synchronzied 和 Lock 的主要区别如下: 存在层面:Syncronized 是Java 中的一个关键字,存在于 JVM 层面,Lock ...

  4. Linux(常用)命令

    目录 Linux(常用)命令 系统信息 关机 (系统的关机.重启以及登出 ) 文件和目录 文件搜索 挂载一个文件系统 磁盘空间 用户和群组 文件的权限 - 使用 "+" 设置权限, ...

  5. 为什么ELT更适合于企业数据应用?

    为什么ELT更适合于企业数据应用 DataPipeline 陈肃 为什么现在企业环境中,一个ELT的方案会比ETL的方案更有优势,实际上是由企业数据应用特点决定的. 首先在一个企业数据应用里面我们对数 ...

  6. android AlertDialog控件使用

    1.先创建activity_alert_dialog.xml <?xml version="1.0" encoding="utf-8"?> < ...

  7. SpringBoot中LocalDatetime作为参数和返回值的序列化问题

    欢迎访问我的个人网站 https://www.zhoutao123.com 本文原文地址 https://www.zhoutao123.com/#/blog/article/59 LocalDatet ...

  8. mybatis中如何将多个表的查询结果,放入结果集中返回

    1.首先需要将resultMap进行改造,为了避免对其他sql的影响建议另外定义一个resultMapExtral,避免id相同, 2.然后在resultMapExtral中添加其它表的字段,若多个表 ...

  9. ISCC之Re2

    硬核rust逆向 首先去学了一天rust...我TMD IDA打开,跟踪主函数 看一下伪代码,发现有一串密文 跟进去发现一串数据,猜测有可能是flag的加密数据,于是回头去分析算法 发现一个关键点 i ...

  10. ffmpeg常用命令-学习

    文章标题:FFmpeg常用命令合集 文章地址:https://blog.csdn.net/lemon_tree12138/article/details/99719520