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;
    } 

  • 相关阅读:
    python打包生成可执行文件教程
    MATLAB中冒号的用法解析
    C#中StreamWriter类使用总结
    C#中StreamReader类读取文件使用示例
    C#中WinFrom保存文件SaveFileDialog类的使用方法
    C#中FolderBrowserDialog类打开文件夹使用说明
    C#中的WinFrom技术实现串口通讯助手(附源码)
    评价指标的计算:accuracy、precision、recall、F1-score等
    【转】一张图解析FastAdmin中的表格列表的功能
    哈工大LTP语言分析:分词、词性标注、句法分析等
  • 原文地址:https://www.cnblogs.com/cherrypill/p/12502584.html
Copyright © 2011-2022 走看看