• Codeforces Round #633 (Div. 1)


    A. Powered Addition (CF 1338 A)

    题目大意

    给定一个(n)个数字的数组(a),对于每一个正整数(x),你可以选择若干个数字(i_1,i_2,i_3,...,i_k),使得(a_{i_j}=a_{i_j}+2^{x-1}, 1 leq j leq k)。当然你也可以不进行选择。求最小的数字(T),使得当(x)取过了(1)~(T)进行操作后,数组(a)是一个非递减数组。

    解题思路

    从左到右,如果(a_i>a_{i+1}),我们就把(a_{i+1})变成(a_i),并记录最大的(a_i-a_{i+1}),最大值在二进制下的位数即是答案。

    操作就很简单,差值在二进制下第(i)位是1就在(x=i)的时候选择那个数就好了。

    神奇的代码
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    int main(void) {
        int kase; read(kase);
        for (int ii = 1; ii <= kase; ++ii) {
            int n;
            read(n);
            int ans=0;
            int qwq=-1e9-7;;
            for(int u,i=1;i<=n;++i){
                read(u);
                if (qwq<=u) qwq=u;
                else{
                    ans=max(ans,qwq-u);
                }
            }
            int cnt=0;
            while(ans){
                ans>>=1;
                ++cnt;
            }
            write(cnt,'
    ');
        }
        return 0;
    }
    


    B. Edge Weight Assignment (CF 1338 B)

    题目大意

    给定一棵无权树,要求对边赋一个正权值,使得任意两个叶子节点之间的路径权值异或和为(0)。求所赋的不同权值数的最小值和最大值。

    解题思路

    如果任意两个叶子节点之间的路径长度是偶数,那么我们对全部边赋(1)即可,最小为(1)

    如果存在奇数长度的,注意到(1igoplus 2igoplus 3=0)。我们把不与叶子节点相连的边赋为(1),是奇数长度的那对叶子节点(a,b)相连的边,一个赋(2),一个赋(3),那其他叶子节点对于这两个叶子节点,如果是偶数路径,则与其叶子节点相连的边的权值一样,奇数路径则相反((2)(3)(3)(2))。

    对于不是(a,b)的一对点(c,d),它们的边权异或和((c,d))一定为(0),因为边权异或和可以拆成((c,d)=(c,a)igoplus(a,d)),因为(c,d)(lca)(a)的边权异或了两次抵消掉了。而在前面的构造里我们知道((c,a)=0,(a,d)=0),所以((c,d)=0)。也即最小为(3)

    判断奇数长度的,从一个叶子节点搜(初始深度为(1))发现有深度是偶数深度的叶子节点即可得知有奇数长度。

    至于最大的,我们可以设想,除了叶子节点相连的边,其他的边都填不同的数,然后选择一个叶子节点(a),其边也填一个不同的数,然后对于其他叶子节点(b),其边填(a,fa[b])的值(fa[b]表示与叶子节点相连的边的另外一个节点)。对于不是叶子节点(a)的点(b,c),其((b,c))也一定为(0),证明也如同上面的方法,将((b,c)=(b,a)igoplus(a,c))

    由于可以填的数无穷大,我们可以证明 (猜想) 这一定可以做到的。

    所以,只有那些一个节点连了多个叶子节点的那些边的权值一定相等外,其他的都可以不一样。

    神奇的代码
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    void DFS(int u,int fa,int deep[],vector<int> edge[]){
        deep[u]=deep[fa]+1;
        for(auto v:edge[u]){
            if (v==fa) continue;
            DFS(v,u,deep,edge);
        }
    }
    
    int dfs(int u,int fa,bool &qwq,int &ans,int deep[],vector<int> edge[],int st){
        int cnt=0;
        int aa=0;
        deep[u]=deep[fa]+1;
        for(auto v:edge[u]){
            if (v==fa) continue;
            ++cnt;
            aa+=dfs(v,u,qwq,ans,deep,edge,st);
        }
        if (!cnt){
            if (!(deep[u]&1)) qwq=true;
            return 1;
        }
        if (fa==st) ++aa;
        ans-=max(0,aa-1);
        return 0;
    }
    
    int main(void) {
        int n;
        read(n);
        vector<int> edge[n+1];
        for(int u,v,i=1;i<n;++i){
            read(u);
            read(v);
            edge[u].push_back(v);
            edge[v].push_back(u);
        }
        int deep[n+1]={0};
        DFS(1,1,deep,edge);
        int st=0,dest=0;
        for(int i=1;i<=n;++i)
            if (dest<deep[i]){
                dest=deep[i];
                st=i;
            }
        deep[st]=0;
        bool qwq=false;
        int ans=n-1;
        dfs(st,st,qwq,ans,deep,edge,st);
        printf("%d %d
    ",(qwq?3:1),ans);
        return 0;
    }
    


    C. Perfect Triples (CF 1338 C)

    题目大意

    有一个有无穷无尽个正整数的数组(s),其构造方法如下:

    • (a<b<c)
    • (a,b,c otin s)
    • (aigoplus bigoplus c=0)
    • (a,b,c)是可选中的字典序最小的一组
    • 把a,b,c依次加入(s)数组的末尾
    • 重复第一步

    现有(t)组询问,每组询问一个数(n),问你数组中第(n)个数(从(1)开始)是多少。

    解题思路

    打表大法好

    注意到(1igoplus 2igoplus 3=0)

    这恰好是(4)进制。于是我们可以把数转成四进制(二进制下俩俩合并),三个数看成一组,对于这一组的数,四进制下每一位我们就可以单独考虑。

    对于最高位,由于(a<b<c),所以最高位上一定是(1、2、3)

    然后对于以下的每一位,只有四种情况:

    • (0 0 0)
    • (1 2 3)
    • (2 3 1)
    • (3 1 2)

    这四种情况也是按照字典序从小到大排好的,其余的情况会出现重复数字。

    按照字典序从小到大构造的三元组的方法就很明显啦,对于三个数的每一位,依次取遍四种情况,然后到下一位。

    这也才造成我们打的表里面,第一个数以(4^n)个分组的结果。

    给定(n)就相当于问第(dfrac{n-1}{3})组(从(0)开始)的第((n-1)\%3)位是多少。

    神奇的代码
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    void work(LL id,LL i,pair<LL,LL> &ans){
        if (i<0) return;
        if (i==0) {
            LL rank=id;
            if (rank==1){
                ans.first^=(1ll<<(i));
                ans.second^=(1ll<<(i+1));
            }else if (rank==2){
                ans.first^=(1ll<<(i+1));
                ans.second^=((1ll<<(i))^(1ll<<(i+1)));
            }else if (rank==3){
                ans.first^=((1ll<<(i))^(1ll<<(i+1)));
                ans.second^=(1ll<<(i));
            }
            return;
        }
        LL cnt=(1ll<<(i));
        work(id%cnt,i-2,ans);
        LL rank=id/cnt;
        if (rank==1){
            ans.first^=(1ll<<(i));
            ans.second^=(1ll<<(i+1));
        }else if (rank==2){
            ans.first^=(1ll<<(i+1));
            ans.second^=((1ll<<(i))^(1ll<<(i+1)));
        }else if (rank==3){
            ans.first^=((1ll<<(i))^(1ll<<(i+1)));
            ans.second^=(1ll<<(i));
        }
    }
    
    int main(void) {
        int t;
        read(t);
        while(t--){
            LL n;
            read(n);
            LL id=(n-1)/3;
            LL pos=(n-1)%3;
            pair<LL,LL> ans;
            ans.first=0;
            ans.second=0;
            for(int i=0;true;i+=2){
                if (id<(1ll<<i)){
                    work(id,i-2,ans);
                    ans.first^=(1ll<<(i));
                    ans.second^=(1ll<<(i+1));
                    break;
                }else id-=(1ll<<i);
            }
            printf("%lld
    ",pos==0?ans.first:(pos==1?ans.second:(ans.first^ans.second)));
        }
        return 0;
    }
    


    不能打(div2)但又虚(div1)......(qwq)

  • 相关阅读:
    【重点推荐】五美凡生论
    语言哲学宣言2018
    四要同环图
    知识分子必须毫不留情反对一切“教养阶层”
    世界上任何一件事的五个模块
    Web 在线制表工具稳定吗?和桌面报表工具对比哪个好用?
    Web 在线制表工具稳定吗?和桌面报表工具对比哪个好用?
    有没有简单易用的数据挖掘工具?
    BI、OLAP、多维分析、CUBE 这几个词是什么关系?
    传说中的中国复杂报表都长什么样?有什么特点?
  • 原文地址:https://www.cnblogs.com/Lanly/p/12709501.html
Copyright © 2020-2023  润新知