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));
    }
}
posted @ 2017-09-01 14:05  阿瓦隆的精灵  阅读(239)  评论(0编辑  收藏  举报