Codeforces Round #628 (Div. 2)(D. Ehab the Xorcist 思维题 E思维+找最小环 F 找环或找独立集)

题目链接

D. Ehab the Xorcist

题意:给你一个u和v 要你构造最短的数组 使得a1^a2...a^n==u  且 a1+a2+a3==v

做法:不会。。。看了别人的做法,我服~ 还是思维太差了,看到这么简单的做法,代码都不想贴了

题解来自:传送门

E. Ehab's REAL Number Theory Problem

题意:给你n个数,要你找最短的序列,这几个序列乘积是一个完全平方数  条件:这n个数最多只有7个除数。

题目初步看起来感觉没一点想法可写,于是我百度题解:传送门

一个数最多是两个质因数,那么对这两个质因数建一条编号为当前i的边,然后跑一个最小环,太妙了

至于怎么找最小环,bfs一下即可,注意不要找到当前点的前驱即可

下面代码是标记了边的编号,替代了这个前驱,也是不错的方法

7
2 3 5 6 12 40 60

对应的图:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int x, n, ans = INT_MAX;
struct node{
    int nxt, eid;
};
vector<node> edges[maxn];
map<pair<int, int>, int> mp;
bool vis[maxn];
int dis[maxn];
queue<int> q;
void Div(int x, int id)
{
    int p = 1, q = 1;
    for(int i = 2; i*i <= x; i++){
        if(x%i==0){
            int num = 0;
            while(x%i==0) num++,x/=i;
            if(num%2){
                if(p==1) p = i;
                else q = i;
            }
        }
    }
    if(x!=1){
        if(p==1) p = x;
        else q = x;
    }
    if(p==1&&q==1){//相当于x==1
        ans = min(ans, 1);
        return ;
    }
    mp[{p, q}]++;
    if(mp[{p, q}]>=2){
        ans = min(ans, 2);
        return ;
    }
    edges[q].push_back({p, id});
    edges[p].push_back({q, id});
}
int bfs(int s)
{
    if(edges[s].empty()) return INT_MAX;
    memset(vis, false, sizeof vis);//记录边是否访问过
    memset(dis, 0, sizeof dis);
    while(!q.empty()) q.pop();
    q.push(s);
    dis[s] = 1;//标记起始点已被访问
    while(!q.empty())
    {
        int now = q.front(); q.pop();
        for(int i = 0; i < edges[now].size(); i++)
        {
            int nxt = edges[now][i].nxt, eid = edges[now][i].eid;
            if(vis[eid]) continue;//边不回返
            if(dis[nxt]) return dis[now]+dis[nxt]-1;
            vis[eid] = true;
            q.push(nxt);
            dis[nxt] = dis[now]+1;
        }
    }
    return INT_MAX;//未成环
}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &x);
        Div(x, i);
    }
    if(ans!=INT_MAX) printf("%d\n", ans);
    else
    {
        for(int i = 1; i <= 1000; i++) ans = min(ans, bfs(i));
        if(ans==INT_MAX) ans = -1;
        printf("%d\n", ans);
    }
    return 0;
}

F. Ehab's Last Theorem

参考来自:传送门

题意:给出n个点m条边的图,找到节点数大于等于sqrt(n)的环或节点数等于sqrt(n)的独立集;

分析:先找环,找不到环证明一定存在有独立集,独立集的找法就是01染色。

找环就记录每个节点的深度即可

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int M=1e5+5;
int flag,vis[M],book[M],deep[M],fa[M],need,ANS2;
vector<int>ans2,ans1,g[M];
void dfs(int u){
    if(flag)
        return;
    vis[u]=1;
    for(auto v:g[u]){
        if(flag)
            return;
        if(v==fa[u])
            continue;
        if(vis[v]){
            if(deep[u]-deep[v]+1>=need){//
                for(int i=u;i!=fa[v];i=fa[i])//找环
                    ans2.pb(i);
                flag=1;
                break;
            }

        }
        else{
            deep[v]=deep[u]+1;
            fa[v]=u;
            dfs(v);
        }
    }
    if(!book[u]){//01染色
        ans1.pb(u);
        for(auto v:g[u]){
            book[v]=1;
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    cin>>n>>m;
    need=ceil(sqrt(n));
    for(int u,v,i=1;i<=m;i++){
        cin>>u>>v;
        g[u].pb(v);
        g[v].pb(u);
    }
    dfs(1);
    if(flag){
//        for(int i=1;i<=n;++i){
//            printf("i:%d de:%d\n",i,deep[i]);
//        }
        cout<<2<<endl;
        cout<<ans2.size()<<endl;
        for(auto v:ans2)
            cout<<v<<' ';
    }
    else{
        cout<<1<<endl;
        for(int i=0;i<need;i++)
            cout<<ans1[i]<<' ';
    }
    return 0;
}
/*
5 5
1 2
1 3
2 4
3 5
4 5
*/
发布了498 篇原创文章 · 获赞 66 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/104879713