zoukankan      html  css  js  c++  java
  • CODEFORCES ROUND #628 (DIV. 2)

    AB日常划水

    C题

    https://codeforces.ml/contest/1325/problem/C

    题目真的容易误解,特别是因为昨天写过博弈论,里面也有mex函数我就以为这个和那个意思差不多|虽然确实差不多

    You are given a tree consisting of nn nodes. You want to write some labels on the tree's edges such that the following conditions hold:

    • Every label is an integer between 00 and n−2n−2 inclusive.
    • All the written labels are distinct.
    • The largest value among MEX(u,v)MEX(u,v) over all pairs of nodes (u,v)(u,v) is as small as possible.

    Here, MEX(u,v)denotes the smallest non-negative integer that isn't written on any edge on the unique simple path from node uu to node vv.Input

    The first line contains the integer n (2≤n≤105) — the number of nodes in the tree.

    Each of the next n−1lines contains two space-separated integers u and v (1≤u,v≤n1≤u,v≤n) that mean there's an edge between nodes u and v. It's guaranteed that the given graph is a tree.Output

    Output n−1n−1 integers. The ithith of them will be the number written on the ithith edge (in the input order).

    题目大意:输入n有n条边,下面n行,每行有a,b代表a,b连一条边问你min(max(mex(u,v))是多少mex(u,v)是 不在 u到v的简单路径中的 其他边的最小整数

    mex1,6就是 2,4 1,3这两条边权值的min (2)

    显然一条链(出入度为2)的情况答案肯定是n-2

     

    先假设有一个出入度为三的点 a,假设边值为0,1,2,因为会枚举到所有点,如果不经过a则mex =0,如果经过a max mex=2 即不能同时经过和这个点相连的三条边

    现在假设有两个不相连的入度为3的点,因为要max mex 最小,所以那两个点边权赋值应该是0,1,2,3,4,5,此时min max mex =5

    现在有两个相连的入度为3的点,那肯定赋值0,1,2,3,4 min max mex=4,由此可见我们应该先给入度为3的点的边赋值,其他的点随便分配都可以上面证明不太严谨,我也是看题解yy的啊

    就是打map的时候手抽定义了hash关键字出来,搞得我ce半天

    make_pair 可以自动辨别所make值的类型返回一个pair类型

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<vector>
    #include<map>
    #include<set>
    #include<utility>
    using namespace std;
    const int N=2e5+5;
    int n,x,y,in[N],tot,ans[N];
    vector <int> f[N];
    map < pair <int ,int > ,int> d; 
    int main()
    {
        scanf("%d",&n);
        memset(ans,-1,sizeof(ans));
        for(int i=1;i<n;i++)
        {
            scanf("%d %d",&x,&y);
            f[x].push_back(y);
            f[y].push_back(x);
            d.insert(make_pair(make_pair(x,y),i));
            d.insert(make_pair(make_pair(y,x),i));
            in[x]++;
            in[y]++;
            //printf("%d
    ",hash[make_pair(y,x)]);
        }
        for(int i=1;i<=n;i++)
        {
            if(in[i]>=3)
            {
                for(int j=0;j<f[i].size();j++)
                {
                    int temp=f[i][j];
                    if(ans[d[make_pair(i,temp)]]==-1)
                    {
                        ans[d[make_pair(i,temp)]]=tot;
                        tot++;
                    }
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<f[i].size();j++)
            {
                int temp=f[i][j];
                if(ans[d[make_pair(i,temp)]]==-1)
                {
                    ans[d[make_pair(i,temp)]]=tot;
                    tot++;
                }
            }
        }
        for(int i=1;i<n;i++)
        {
            printf("%d
    ",ans[i]);
        }
        return 0;
     } 

    D题

    https://codeforces.ml/contest/1325/problem/D

    这么短的题就自己读一下吧...

    u=a xor b,v=a+b,a,b为非负整数

    显然v<u的时候是无解的因为v=a+b=u+2∗(a&b)(a&b>=0)

    异或的性质1: x xor 0 =x 所以u==v的时候 可以构造出0,u满足条件(0,0特判)这时输出1 u (因为说了输出只有正整数)

    根据上面的性质可继续推 x xor y xor y= x 所以 猜测x =u,2*y+x=v

    所以y=a&b=(u-v)/2,if u-v%2!=0也无解

    否则因为一定存在 这样的x,y满足题意,所以最大长度是3(x,y,y)

    现在枚举一下x,y两两组合看能不能满足题意就好了 (就是看(x+y)xor y和x xor 2*y 满不满足就可以了

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    long long u,v;
    int main()
    {
        scanf("%lld %lld",&u,&v);
        if(v<u)
            printf("-1
    ");
        if(v==u)
        {
            if(u==0)
                printf("0
    ");
            else
                printf("1
    %lld
    ",u);
        }
        if(v>u)
        {
            if((v-u)%2)
                printf("-1
    ");
            else
            {
                long long b=(v-u)/2;    
                if((u^(v-u))==u)
                    printf("2
    %lld %lld
    ",u,v-u);
                else if(((u+b)^b)==u) printf("2
    %lld %lld
    ",u+b,b);
                else 
                    printf("3
    %lld %lld %lld",u,b,b);
            }
        }
        return 0;
     } 

    记得开longlong和0,0特判

    E题

    https://codeforces.ml/contest/1325/problem/E

    You are given an array aa of length nn that has a special condition: every element in this array has at most 7 divisors. Find the length of the shortest non-empty subsequence of this array product of whose elements is a perfect square.

    A sequence aa is a subsequence of an array bb if aa can be obtained from bb by deletion of several (possibly, zero or all) elements.Input

    The first line contains an integer n (1≤n≤10^5) — the length of aa.

    The second line contains nn integers a1, a2, ……, an (1≤ai≤10^6) — the elements of the array aa.Output

    Output the length of the shortest non-empty subsequence of aa product of whose elements is a perfect square. If there are several shortest subsequences, you can find any of them. If there's no such subsequence, print "-1".

    题目大意:给你n个数,a1,a2,...an,保证ai的约数个数小于7,让你从这n个数中选取最少的数 是他们相乘结果为完全平方数,输出最小 选取数的个数

    可以证明约数个数小于7则分解质因数后肯定小于3个不同质因数,(1,p,q,w,qp,qw,pw,pqw 八个了)如果有相同的质因数,处理一下,把偶数次幂去掉(对结果没有影响可以直接无视),最后剩下奇数次幂的质因数肯定也最多只有两个,我们可以构造一个图(不一定连通),节点就是质因数,

    如果节点被连了几边说明几个数中有这个质因数,我们只要找到一条路径,这条路上的点全是偶数条边即可(这个路径肯定是环),因为如果选的节点不构成一个环,则末尾节点肯定是奇数,所以我们只要枚举每一个点找出这个图中的最小环就行了

    但是枚举每一个点肯定超时,想到 求因数的优化方法,我们可以类推到如果一个因数大于sqrt max ai 的节点q,则它肯定连着小于sqrt max ai 的节点p,因为我们是按顺序枚举的,枚举p的时候肯定就q情况判断出来了,就不用再枚举q了。

    建图:

    1 如果是因数是q,p, 则pq连一条边 (p-q)

    2 如果因数只有p 则p-1

    3 如果只有1 或他本身就是完全平方数 直接输出 1

    4 如果除了3还有重复的数输出 2

    数字预处理真的难搞

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<vector>
    #include<map>
    #include<queue>
    #include<set>
    #include<utility>
    #include<cmath> 
    using namespace std;
    const int N=2e5+5,M=1e6+5,inf=2147483647;
    int n,x,dis[M],a[M],ss[M],k,tot,ans=inf;
    bool use[M];
    vector <int> g[M];
    queue <int> q;
    set < int > s1,s2;
    void bfs(int x) //找最小环
    {
        for (auto i:s2)
             dis[i]=inf,use[i] = 0;
        while(!q.empty())
            q.pop();
        memset(use,0,sizeof(use));
        dis[x]=0;
        q.push(x);
        use[x]=1;
        while (!q.empty()) 
        {
            int top = q.front();
            q.pop();
            use[top] = false;
            for (auto i:g[top]) 
            {
                if (dis[i] > dis[top] + 1) 
                {
                    dis[i] = dis[top] + 1;
                    q.push(i);
                    use[i] = true;
                }
                else 
                    if (use[i]) 
                    {
                        ans = min(ans, dis[top] + dis[i] + 1);
                    }
            }
        }
    }
    int init(int x) //初步化简掉偶数次幂的因数
    {
        for (int i = 2; i * i <= x; ++i) 
        {
            if (x % i) continue;
            int cnt = 0;
            while (x % i == 0) x /= i, ++cnt;
            if (cnt & 1) x *= i;
        }
        return x;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            x=init(x); 
            s1.insert(x);
        }
        if(s1.count(1)==1) 
        { 
            printf("1
    "); 
            return 0; 
        }
        if(int(s1.size())<n) 
        { 
            printf("2
    "); 
            return 0; 
        }
        for (auto i : s1)//枚举化简后数的因数 
        {
            int tmp[2];
            tmp[0]=tmp[1]=-1;
            tmp[0] = i;
            for (int j = 2; j * j <= i; ++j) 
            {
                if (i % j) 
                    continue;
                tmp[0] = j;
                i /= j;
                if (i != 1) 
                    tmp[1] = i;
                break;
            }
            if (tmp[1] == -1) 
                tmp[1] = 1;
            for (auto j : tmp) 
                s2.insert(j);//将每个节点放入集合中之后好枚举 
            g[tmp[0]].emplace_back(tmp[1]);
            g[tmp[1]].emplace_back(tmp[0]);
        }
        //因为如果节点大于sqrt(max ai)肯定只会被连一条边(奇数),就和公因数i*i<j类似 
        //肯定不会成环直接排除,所以从2~1000里面选节点 
        for(int i=2;i<=1000;i++)
        {
            if(s2.count(i)==0)
                continue;
            bfs(i);
        } 
        if(ans==inf)
            ans=-1; 
        printf("%d
    ",ans);
        return 0;
    } 

  • 相关阅读:
    Codeforces 1316B String Modification
    Codeforces 1305C Kuroni and Impossible Calculation
    Codeforces 1305B Kuroni and Simple Strings
    Codeforces 1321D Navigation System
    Codeforces 1321C Remove Adjacent
    Codeforces 1321B Journey Planning
    Operating systems Chapter 6
    Operating systems Chapter 5
    Abandoned country HDU
    Computer HDU
  • 原文地址:https://www.cnblogs.com/cherrypill/p/12502584.html
Copyright © 2011-2022 走看看