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\n",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\n",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\n u\n(因为说了输出只有正整数)

根据上面的性质可继续推 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\n");
    if(v==u)
    {
        if(u==0)
            printf("0\n");
        else
            printf("1\n%lld\n",u);
    }
    if(v>u)
    {
        if((v-u)%2)
            printf("-1\n");
        else
        {
            long long b=(v-u)/2;    
            if((u^(v-u))==u)
                printf("2\n%lld %lld\n",u,v-u);
            else if(((u+b)^b)==u) printf("2\n%lld %lld\n",u+b,b);
            else 
                printf("3\n%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\n"); 
        return 0; 
    }
    if(int(s1.size())<n) 
    { 
        printf("2\n"); 
        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\n",ans);
    return 0;
} 

 

 

posted @ 2020-03-16 11:15  Sakura_Momoko  阅读(199)  评论(0编辑  收藏  举报