CodeCraft-21 and Codeforces Round #711 (Div. 2)
作者:互联网
A. GCD Sum
题目描述
设 \(s(i)\) 为 \(i\) 的数位和,求第一个 \(\geq n\) 满足下式的 \(x\):
\[\gcd(x,s(x))>1 \]\(1\leq n\leq 10^{18}\),数据组数不超过 \(10^4\) 组
解法
一开始没想法,然后打了个爆搜过掉了。
根据小学奥数可知若 \(x\) 为 \(3\) 的倍数则 \(\gcd(x,s(x))=3\),所以就算是爆搜也只需要搜三次。
B. Box Fitting
题目描述
解法
又猜了结论,就是能填大的就暴力填大的。
证明就考虑如果某次放弃了填大的机会,那么我们肯定会填小的,但是若干个小的一定等价于一个大的,因为小的都是大的因数。那么既然是等价的填大的可以让以后的选择更灵活,所以贪心成立。
E. Two Houses
题目描述
解法
再次猜结论,就是入度小的点一定能到达入度大的点,然后随便搞一下就 \(\tt A\) 了。
证明:设两个点的入度分别是 \(a,b(a\leq b)\),那么 \(a\) 连出去的边有 \(n-1-a\) 条,\(b\) 连进来的边有 \(b\) 条,只考虑这些边构成的图,如果没有点重复被边连那么总点数是 \(n-1-a+b+2=n+1+(b-a)\geq n+1\),这说明一定有点重复,那么 \(a\) 对应的点可以到达 \(b\) 对应的点。
F. Christmas Game
题目描述
解法
首先考虑对于一个固定的根怎么做?发现模 \(k\) 不同的深度是互不干扰的,所以可以分开来考虑,因为是博弈问题所以可以使用 \(\tt sg\) 函数把每个子问题合并起来,现在考虑子问题即可。
发现子问题其实就是阶梯博弈:有长度为 \(n\) 的阶梯,每次可以把某个阶梯上的石子移动到上一个阶梯,如果移动到地面则不能移动,不能操作者输。那么这个游戏的 \(\tt sg\) 函数就是奇数位置上石子的异或和。
证明:我们找出一种状态,让某个人可以维持这种状态,直到另一个人输掉。如果先手遇到的状态是奇数位置上石子异或和为 \(0\),如果先手操作奇数位置后手可以让奇数位置异或和恢复 \(0\)(\(\color{red}tag\)),如果先手操作偶数位置那么后手把等量的石子移回奇数位置,那么后手必胜。如果先手遇到的状态是奇数位置上石子异或和非 \(0\),那么先手可以一步操作让奇数位置异或和变成 \(0\),先手必胜(\(\color{red}tag\))。
打了 \(\color{red}tag\) 可能是你要把下面的东西读完才能搞清楚的,下面证明 \(\tt sg\) 函数的子问题组合定理:
如果一个游戏由很多独立子游戏构成,那么 \(\tt sg\) 值为所有子游戏的 \(\tt sg\) 值的异或:
\[f(x)=\bigoplus_{i=1}^nf_i(x_i) \]证明考虑归纳法,最终的状态(先手输)一定满足这个等式,我们假设某个状态的后继状态满足这个定理,那么只需要证明这个状态也满足就行了,设 \(b=\bigoplus_{i=1}^n f_i(x_i)\)。
假设后继让子游戏 \(j\) 的状态 \(x_j\) 变成了 \(x_j'\),它的 \(\tt sg\) 函数就是 \(b\oplus f_j(x_j)\oplus f_j(x_j')\)
根据 \(\tt mex\) 的定义,我们只需要证明两点:
- \(\forall a\in[0,b)\),存在 \(x_j'\) 满足 \(b\oplus f_j(x_j)\oplus f_j(x_j')=a\),我们可以取最大的 \(f_j(x_j)\),那么这个子问题的后继满足 \(f(x_j')\) 能够取遍 \([0,f_j(x_j))\),我们可以让 \(b\) 的某一个位由 \(1\) 变 \(0\),那么较低的那些位就可以随便取,也就是说可以构造出任意数。这个证明方法可以说明 \(\color{red} tag\) 的结论,我们取最大的奇数位置的石子操作即可。
- \(\forall x_j',b\oplus f_j(x_j)\oplus f_j(x_j')\not=b\),这个东西在 \(f_j(x_j)=f_j(x_j')\) 的时候不成立,但是根据 \(\tt mex\) 的定义上述情况是不会发生的。
所以 \(\tt mex\) 和 \(\oplus\) 这两个奇怪的东西就产生了神秘的 \(\tt sg\) 函数!
知道了上面这些东西之后就好做了,因为 \(k\leq20\) 所以可以暴力换根,记 \(f[u][i]\) 表示以 \(u\) 为根模 \(2k\) 为 \(i\) 的深度的石子异或和即可。
#include <cstdio>
const int M = 100005;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,k,tot,a[M],f[M],g[M],ans[M],dp[M][45];
struct edge
{
int v,next;
}e[2*M];
void pre(int u,int fa)
{
dp[u][0]^=a[u];
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==fa) continue;
pre(v,u);
for(int j=0;j<2*k;j++)
dp[u][(j+1)%(2*k)]^=dp[v][j];
}
}
void dfs(int u,int fa)
{
for(int i=k;i<2*k;i++) ans[u]^=dp[u][i];
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==fa) continue;
for(int j=0;j<2*k;j++)
g[(j+1)%(2*k)]=dp[u][(j+1)%(2*k)]^dp[v][j];
for(int j=0;j<2*k;j++)
dp[v][(j+1)%(2*k)]^=g[j];
dfs(v,u);
}
}
signed main()
{
n=read();k=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read();
e[++tot]=edge{v,f[u]},f[u]=tot;
e[++tot]=edge{u,f[v]},f[v]=tot;
}
for(int i=1;i<=n;i++)
a[i]=read();
pre(1,0);
dfs(1,0);
for(int i=1;i<=n;i++)
printf("%d ",ans[i]!=0);
}
标签:CodeCraft,21,奇数,tt,石子,Codeforces,异或,oplus,sg 来源: https://www.cnblogs.com/C202044zxy/p/14729256.html