Codeforces Round #430 (Div. 2)题解
Codeforces Round #430 (Div. 2)题解
A、B
签到题,略
C. Ilya And The Tree
题意
有一颗树,每个点上有一个权重,定义每个点的美丽值为根到这个点上路径gcd的最大值,在每次计算时可以有一次机会将一个点的权重暂时变为0,输出每个节点的美丽值
wa到最后10分钟左右才发现读错题了,原来以为是从根经过x到叶子的路径……,当时还觉得稍微改一下就能过了,没想到思路都是错的
思路
所以说自己还是思维僵化,看到这种树上路径的题就想用树形DP,还设计了一个DP的状态,其实想想由于是gcd,最终的最优状态未必是由两个局部的最优状态转移过来的。
正确的解法是用直接用set维护所有可能的值就可以了,在dfs的过程中由父节点的所有可能值更新子节点的值
时间复杂度\(O(nlgn)\),其实看到\(2e5\)这样一个数据大小就应该反应过来是这个复杂度的……,非要搞什么\(O(n)\)的DP
AC代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+7;
set <int> s[maxn];
int a[maxn],n;
vector <int> sons[maxn];
void dfs(int u,int fa,int now)
{
for (auto &num: s[fa])
s[u].insert(__gcd(num,a[u]));
s[u].insert(now);
now=__gcd(now,a[u]);
s[u].insert(now);
for (auto &v: sons[u])
if(v!=fa)
dfs(v,u,now);
return;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
sons[u].push_back(v);
sons[v].push_back(u);
}
dfs(1,0,0);
for (int i=1;i<=n;i++)
printf("%d%c",*s[i].rbegin()," \n"[i==n]);
}
D. Vitya and Strange Lesson
题意
定义\(mex(a[i])\)为数组\(a\)中没有出现的最小的自然数,有m个询问,每个询问输入一个数\(k\),数组\(a\)的所有数都异或上\(k\)后,输出\(mex(a[i])\)
思路
对于异或的常见处理方法是建立\(01trie\),但是每次对所有的数全部进行异或过于麻烦,设\(k\) 为所有输入过的查询异或在一起的结果,注意到\(a \oplus k =b\),那么\(a =b \oplus k\) ,问题可以转化为找到最小的\(b, s.t. b \oplus k\)没有在\(a\)数组中出现过,先对所有没有出现在\(a\)数组中的数建立一个\(01trie\), 在树中查找\(b \oplus k\),为了使\(b\)尽量小,我们从高位向低位查找,尽量让每一位都与\(k\)相同(\(b \oplus k \oplus k= b\) ,让尽量高的位为\(0\) )
\(Tips:\) \(b \oplus k\)的大小是可能大于数据的上界的,所以处理没有出现过的数的时候上界要高于数据的上界,我这里直接取了\(600000\)
时间复杂度:$ O(m lgn)$
AC代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=3e5+7;
int n,m,a[maxn];
bool vis[maxn*2];
struct Trie
{
int ch[maxn*50][2];
int sz;
Trie(){sz=1;memset(ch[0],0,sizeof(ch[0]));}
void insert(int s)
{
int u=0,n=21;
for (int i=n-1;i>=0;i--)
{
int c=(s>>i)&1;
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(sz));
ch[u][c]=sz++;
}
u=ch[u][c];
}
}
int query(int s)
{
int u=0,n=21,ret=0;
for (int i=n-1;i>=0;i--)
{
int c=(s>>i)&1;
if(!ch[u][c]) c^=1;
ret|=(c<<i);
u=ch[u][c];
if(!ch[u][0]&&!ch[u][1]) break;
}
return ret^s;
}
}trie;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) vis[a[i]]=true;
for (int i=0;i<=600000;i++)
if(!vis[i])
trie.insert(i);
int now=0,k=0;
for (int i=1;i<=m;i++)
{
scanf("%d",&k);
now^=k;
printf("%d\n",trie.query(now));
}
}