Codeforces Round #628 (Div. 2) 总结

A

输出 \(1,n-1\)

#include <bits/stdc++.h>
using namespace std;

signed main() {
    int t,a,b;
    cin>>t;
    while(t--) {
        cin>>a;
        cout<<1<<" "<<a-1<<endl;
    }
}

B

不同数字个数

#include <bits/stdc++.h>
using namespace std;

set<int> s;
int t,n,a[100005];

signed main() {
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--) {
        cin>>n;
        for(int i=1;i<=n;i++) {
            cin>>a[i];
            if(s.find(a[i])==s.end()) s.insert(a[i]);
        }
        cout<<s.size()<<endl;
        s.clear();
    }
}

C

给树上所有边分配边权 \(0,1,...,n-2\),要求任意两点的路径上的 MEX 的最大值最小

如果树是一条链,答案为 \(n-1\),边权随便设

如果树不是链,答案为 \(2\),找到一个度数大于 \(2\) 的点,找到它的任意三条边,令其为 \(0,1,2\),其它的随便设

#include <bits/stdc++.h>
using namespace std;

const int N = 200005;
int n,u,v,d[N],a[N];
vector <int> id[N];

signed main() {
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<n;i++) {
        cin>>u>>v;
        d[u]++;
        d[v]++;
        id[u].push_back(i);
        id[v].push_back(i);
    }
    int p=max_element(d+1,d+n+1)-d;
    if(d[p]<=2) {
        for(int i=1;i<n;i++) cout<<i-1<<endl;
    }
    else {
        a[id[p][0]]=1;
        a[id[p][1]]=2;
        a[id[p][2]]=3;
        int ind=3;
        for(int i=1;i<n;i++) if(a[i]==0) a[i]=++ind;
        for(int i=1;i<n;i++) cout<<a[i]-1<<endl;
    }
}

D

给定 \(u,v \leq 10^{18}\),求长度最短的数组,使得异或和为 \(u\),代数和为 \(v\)

如果 \(u,v\) 奇偶性不同,或 \(u>v\),则一定不合法

所以 \(v-u\) 一定是偶数,直观地,我们可以用 \(u,(v-u)/2,(v-u)/2\) 来表示,但这当中有一些是非最优的,也有一些是非法的

当且仅当 \(u=v=0\),输出一个空数组即可

当且仅当 \(u=v\),上述表示非法,而此时只需要这个数本身就可以了,\(n=1\)

考虑何时 \(n=2\)

显然 \(u=0\) 时可以

另一种情况是, \((v+u)/2, (v-u)/2\) 的异或值等于 \(u\)

#include <bits/stdc++.h>
using namespace std;

#define int long long
int u,v;

signed main() {
    cin>>u>>v;
    if((u-v)%2 || u>v) cout<<-1;
    else if(u==0&&v==0) cout<<0;
    else if(u==v) cout<<1<<endl<<u;
    else if(u==0) cout<<2<<endl<<v/2<<" "<<v/2;
    else if((((v+u)/2)^((v-u)/2))==u) cout<<2<<endl<<(v+u)/2<<" "<<(v-u)/2;
    else cout<<3<<endl<<u<<" "<<(v-u)/2<<" "<<(v-u)/2;
}

E

给一些数,每个数的因数个数不超过 \(7\),求最少选出多少个使得乘积为完全平方数

由于每个数的因数个数不超过 \(7\),每个数的质因子个数一定 \(\leq 2\)

那么一个很直观的想法是,对于质因子个数为 \(2\) 的数,我们可以将质因子设为结点,那么这些数就是边

如果一个数的质因子只有一个(如果有两个质因子且某个质因子的幂指数是 \(2\) 我们就当做 \(0\) 处理),则额外构建一个 \(1\) 结点,将这个质因子与 \(1\) 连边来表示这个数

如果一个数只有一个质因子并且幂指数为 \(2\),就当做自环,或者这时直接输出 \(1\) 然后结束

经过这样的建图后,找这个图中的最小环就是答案

发现环内必有一个点 \(\leq \sqrt{\max a_i}\)

于是只从这些数开始暴力 BFS 即可

F

给定无向图,找出至少有 \(\lceil \sqrt n \rceil\) 个点的环,或者正好有 \(\lceil \sqrt n \rceil\) 个点的独立集

建立一棵 DFS 树,枚举所有非树边,如果找到某个非树边连接的两个点深度之差 \(\geq [\sqrt n]-1\),则输出之

否则一定有符合条件的独立集,于是我们仍然把图 DFS 一遍,对于一个点,能选就选,并将相邻所有点打标记即可

注意打标记是在处理完这个点的所有相邻点之后,方可保证最优(这个地方感觉很诡异,最后一分钟瞎改改过的)

#include <bits/stdc++.h>
using namespace std;

const int N = 500005;

int n,m,t1,t2,t3,lim;
int dep[N],vis[N],fg[N];
vector <int> g[N];
vector <int> sta;

void dfs1(int p) {
    sta.push_back(p);
    vis[p]=1;
    for(int q:g[p]) {
        if(!vis[q]) {
            dep[q]=dep[p]+1;
            dfs1(q);
        }
        else {
            if(dep[q] && dep[p]-dep[q]>=lim-1) {
                cout<<2<<endl<<dep[p]-dep[q]+1<<endl;
                while(sta.back()!=q && sta.size()) {
                    cout<<sta.back()<<" ";
                    sta.pop_back();
                }
                cout<<q<<endl;
                exit(0);
            }
        }
    }
    sta.pop_back();
}

void dfs2(int p) {
    vis[p]=1;
    for(int q:g[p])
        if(!vis[q]) dfs2(q);

    for(int q:g[p]) if(!fg[p]) fg[q]=1;
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    lim=1;
    while(lim*lim<n) ++lim;
    for(int i=1;i<=m;i++) {
        cin>>t1>>t2;
        g[t1].push_back(t2);
        g[t2].push_back(t1);
    }
    dep[1]=1;
    dfs1(1);
    memset(vis,0,sizeof vis);
    dfs2(1);
    int cnt=lim;
    cout<<1<<endl;
    for(int i=1;i<=n && cnt;i++) {
        if(!fg[i]) cout<<i<<" ", --cnt;
    }
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12521351.html