Codeforces Round #738(Div.2)

Codeforces Round #738(Div.2)

比赛链接:https://codeforces.com/contest/1559
A - Mocha and Math

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
 /*因为操作次数是任意的,每次一个数&上另一个数肯定是会变小的,
 那么最小的最大值值就是所有数&起来。 */
using namespace std ;
 
const int N = 105;
int n,a[N];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int ans=0;
        scanf("%d", &n);
        for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
        int res=a[0];
        for (int i = 1; i < n; i ++ )
        {
            res=res&a[i];
        }
            
        printf("%d\n",res);
    }
    return 0 ; 
}

B - Mocha and Red and Blue

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

char a[110];

int main() {
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin>>n;
        scanf("%s", a+1); //将字符串存在1~n
        int pos=-1;
        for (int i = 1; i <= n; i ++ )
            if(a[i]!='?') //找到第一个不是问号的字符串的位置
            {
                pos=i;
                break;
            }
        
        if(pos==-1) //pos=-1代表所有字符串都是问号
        {
            for(int i=1;i<=n;i++)
            {
                if(i&1) a[i]='B';
                else a[i]='R';
            cout<<a[i];
            }
        }
        else
        {
            for(int i=pos-1;i>=1;i--) //从第一个不是问号的字符串前一个位置向前遍历
               if(a[i+1]=='B') a[i]='R'; //与后面一个取相反的
               else a[i]='B';

        for(int i=1;i<pos;i++) cout<<a[i]; //输出前pos-1个
        
        for(int i=pos;i<=n;i++)
        {
           if(a[i]=='?')
           {
               if(a[i-1]=='B') a[i]='R';
               else a[i]='B';
           }
           cout<<a[i];
        }
        }
        puts("");
    }
    return 0;
}

C - Mocha and Hiking

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 10010;

int a[N];

int main() {
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
        
        bool flag=false; //如果最后flag=false表示无解
        int pos=-1; //记录插入n+1的位置
        for (int i = 2; i <= n; i ++ )
            if(a[i] && !a[i-1]) //遍历,寻找是否有可以插入n+1的位置(在i-1和i之间)
            {
                pos=i;
                break;
            }
        if(a[1]) //如果n+1号点可以向1号点连一条边
        {
            flag=true;
            cout<<n+1<<' ';
            for(int i = 1; i <= n; i ++ ) cout<<i<<' ';
        }
        else if(a[n]==0) //如果n号点可以向n+1号点连一条边
        {
            flag=true;
            for(int i = 1; i <= n; i ++ ) cout<<i<<' ';
            cout<<n+1;
        }
        else if(pos!=-1) //或者如果1~n中有位置可以插入n+1
        {
            flag=true;
            for (int i = 1; i <= n; i ++ )
            {
                if(i==pos) cout<<n+1<<' ';
                cout<<i<<' ';
            }
        }
            
        if(!flag) puts("-1");
        puts("");
    }
    return 0;
}

D1 - Mocha and Diana (Easy Version)

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
//并查集裸题,n^2遍历所有边,每次判断是否可以同时加入到两棵树中即可
using namespace std;

typedef pair<int, int> PII;

const int N = 10010;

int n,m1,m2;
int p1[N],p2[N];

int find(int x,int p[])  
{
    if (p[x] != x) p[x] = find(p[x],p);
    return p[x];
}

int main() {
    scanf("%d%d%d",&n,&m1,&m2);
    
    for (int i = 1; i <= n; i ++ ) p1[i]=i;
    for (int i = 1; i <= n; i ++ ) p2[i]=i;
    
    int u,v;
    for (int i = 0; i < m1; i ++ )
    {
        scanf("%d%d", &u, &v);
        u=find(u,p1),v=find(v,p1); 
        if(u!=v) p1[u]=v;
//注意!此处一定要判断根节点是否相同,因为已有边会出现相同一点,如:(2,5),(2,9),这时就会
//出现前面这个点被加到一个集合中,后面又被加到另一个集合中的情况,会WA(惨痛教训!)
    }
    for (int i = 0; i < m2; i ++ )
    {
        scanf("%d%d", &u, &v);
        u=find(u,p2),v=find(v,p2);
        if(u!=v) p2[u]=v;
    }
    int res=0;
    vector<PII> ans; //用vector+pair来存边
    for (int i = 1; i <= n; i ++ ) //暴力枚举所有边
        for (int j = i + 1; j <= n; j ++ )
        {
            int a,b,c,d;
            a=find(i,p1),b=find(j,p1),c=find(i,p2),d=find(j,p2);
            if(a!=b && c!=d)
            {
                p1[a]=b;
                p2[c]=d;
                res++;
                ans.push_back({i,j});
            }
        }
    cout<<res<<endl;
    for(PII i:ans) cout<<i.first<<' '<<i.second<<endl;
    return 0;
}

D2 - Mocha and Diana (Hard Version)
D2与D1题意完全一致,只是数据范围扩大了,导致我们不能再用n^2的方法去暴力,参考巨巨们的题解知道了一种解法,即在所有节点中选择一点作为根节点(我这里选择的是1),先O(n)遍历所有节点,判断在树1和树2中是否都可以合并到根节点,可以的话在该节点和根节点间连一条边并输出,然后剩下的就是两种情况:只在树1中可以合并到根节点和只在树2中可以合并到根节点,于是我们O(n)遍历,将这些节点分别存入两个数组res1、res2,最后进行两两配对连接起来(最大配对数量为两数组中较小的那个)。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 100010;

int n,m1,m2;
int p1[N],p2[N];

int find(int x,int p[])  
{
    if (p[x] != x) p[x] = find(p[x],p);
    return p[x];
}

int main() {
    scanf("%d%d%d",&n,&m1,&m2);
    
    for (int i = 1; i <= n; i ++ ) p1[i]=i;
    for (int i = 1; i <= n; i ++ ) p2[i]=i;
    
    int u,v;
    for (int i = 0; i < m1; i ++ )
    {
        int l,r;
        scanf("%d%d", &u, &v);
        l=find(u,p1),r=find(v,p1);
        if(l!=r)
        {
           if(l<r) p1[r]=l;
           else p1[l]=r;
        } //让较小的节点当父节点,以保证之后在有1的集合中1为祖宗节点
    }
    for (int i = 0; i < m2; i ++ )
    {
        int l,r;
        scanf("%d%d", &u, &v);
        l=find(u,p2),r=find(v,p2);
        if(l!=r)
        {
           if(l<r) p2[r]=l;
           else p2[l]=r;
        }
    }
    int res=0;
    vector<int> res1,res2;
    
    cout<<n-1-max(m1,m2)<<endl; //最大连接边数为总边数减去两棵树中已连边数最大值
    for (int i = 2; i <= n; i ++ ) //必须先将两张图中均不在1这棵树上的点并入1这个集合
        {
            int a,b;
            a=find(i,p1),b=find(i,p2);
            if(1!=a && 1!=b)
            {
                p1[a]=1;
                p2[b]=1;
                cout<<1<<' '<<i<<endl;
            }    
        }
/*遍历2~n,将只在树1上的点和只在树2上的点连接起来得到最终答案
(一张图连上了1,另一张没有连上1,那么这时的点i有可能与接下来某个点j连接,
从而使它合理地连上1,所以这里把它存进栈里。)
*/
    for (int i = 2; i <= n; i ++ ) 
        {
            int a,b;
            a=find(i,p1),b=find(i,p2);
            if(1!=a)
            {
                res1.push_back(i);
                p1[a]=1;
            }
            else if(1!=b)
            {
                res2.push_back(i);
                p2[b]=1;
            }
        }
    int rlength=min(res1.size(),res2.size());

    for(int i=0;i<rlength;i++) 
       cout<<res1[i]<<' '<<res2[i]<<endl;
    return 0;
}

E - Mocha and Stars

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值