Codeforces Round #738 (Div. 2)

本文通过四个不同的编程问题,探讨了数组操作和字符串处理的策略。包括:1) 对数组元素进行位运算求最小最大值;2) 字符串相邻字符匹配最小化;3) 图形路径规划确保遍历所有节点;4) 并查集应用在无环图连接操作。通过实例解析,展示了如何运用贪心、位运算和并查集等算法解决实际问题。
摘要由CSDN通过智能技术生成

A、Mocha and Math

题意:

给定一个长度为n的数组,你可以任选一个区间 [ l , r ] [l,r] [l,r]进行操作,对于这个区间的所有值
i ( 0 ≤ i ≤ r − l ) i (0≤i≤r−l) i(0irl),将 a l + i a_{l+i} al+i替换为 a l + i a_{l+i} al+i& a r − i a_{r−i} ari。你可以进行无数次操作,让你求最后经过若干次操作后的数组中 最小的最大值是多少。

思路:

签到题,我们注意到可以 任选一个区间,进行无数次操作。并且每次进行&运算肯定会让&运算后的数小于等于原来的值,所以最小的最大值肯定就是把所有数进行&运算得到的数。因为其中的最大值想变小,肯定要去和其他比他更小的值进行&运算,前面提到了每次&之后,只会让原来的数变小或者不变,所以对所有数进行&运算一定会得到所求答案。

代码:

#include<bits/stdc++.h>
//#pragma GCC optimize(2)
using namespace std; 
#define int long long
#define fi first
#define se second
#define endl '\n'
#define PII pair<int,int>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
const int N=1e6+5;
int h[N],e[N],nx[N],idx;
int k,T,t,n,m,ans,cnt;
int a[N];
bool vis[N];
priority_queue <int,vector<int>,greater<int> > q;
signed main()
{
        ios::sync_with_stdio(false);
         cin.tie(0),cout.tie(0);
        cin>>T;
        while(T--)
        {
                cin>>n;
                for(int i=1;i<=n;i++) cin>>a[i];
                int ans=a[1];
                for(int i=2;i<=n;i++)
                        ans&=a[i];
                cout<<ans<<endl;
        }

        return 0;
}

B、Mocha and Red and Blue

题意:

给定一个长度为n的字符串,其中会出现B,R,’ ?'三个字符,你可以把‘ ?’可以变成B或R。让你输出一个字符串,使任意两个相邻位置的两个字符相等的情况最小。

思路:

直接贪心即可,因为n非常的小,仅有100,那我们直接暴力 n 2 n^2 n2即可。若遇到一个非’ ?‘的字符,就去遍历它的前面和后面,如果遍历的时候遇到非’ ?‘就直接break即可,如果遇到’ ?‘的话就看’ ?‘与他的位置差了是奇数还是偶数,若是偶数则让’ ?'变成和它一样的字母,若为奇数则变成另外一个字母即可。不过这里还要特判一下全为‘ ?’这种情况,这种情况的话我们直接按照BRBRBR输出即可,当然RBRBRB也是一样的。

代码:

#include<bits/stdc++.h>
//#pragma GCC optimize(2)
using namespace std; 
#define int long long
#define fi first
#define se second
#define endl '\n'
#define PII pair<int,int>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
const int N=1e6+5;
int h[N],e[N],nx[N],idx;
int k,T,t,n,m,ans,cnt;
char s[N];
bool vis[N];
priority_queue <int,vector<int>,greater<int> > q;
signed main()
{
        ios::sync_with_stdio(false);
         cin.tie(0),cout.tie(0);
        cin>>T;
        while(T--)
        {
                cin>>n;
                cin>>s+1;
                s[n+1]='0';
                bool fl=false;
                for(int i=1;i<=n;i++)
                {
                        if(s[i]=='B')
                        {
                                fl=true;
                                bool flag=true;
                                for(int j=i-1;j>=1;j--)
                                {
                                        if(flag&&s[j]=='?') s[j]='R';
                                        else if(!flag&&s[j]=='?') s[j]='B';
                                        else break;
                                        flag=!flag;
                                }
                                flag=true;
                                for(int j=i+1;j<=n;j++)
                                {
                                        if(flag&&s[j]=='?') s[j]='R';
                                        else if(!flag&&s[j]=='?') s[j]='B';
                                        else break;
                                        flag=!flag;
                                }                                
                        }
                        else if(s[i]=='R')
                        {
                                fl=true;
                                bool flag=true;
                                for(int j=i-1;j>=1;j--)
                                {
                                        if(flag&&s[j]=='?') s[j]='B';
                                        else if(!flag&&s[j]=='?') s[j]='R';
                                        else break;
                                        flag=!flag;
                                }
                                flag=true;        
                                for(int j=i+1;j<=n;j++)
                                {
                                        if(flag&&s[j]=='?') s[j]='B';
                                        else if(!flag&&s[j]=='?') s[j]='R';
                                        else break;
                                        flag=!flag;
                                }                                                                
                        }        
                }        
                if(!fl)
                {
                        bool flag=true;
                        for(int i=1;i<=n;i++)
                        {
                                if(flag) s[i]='B';
                                else s[i]='R';
                                flag=!flag;
                        }
                }
                for(int i=1;i<=n;i++) cout<<s[i];
                cout<<endl;
        }

        return 0;
}

C、Mocha and Hiking

题目:

给定 n + 1 n+1 n+1个村庄,以及 2 n − 1 2n-1 2n1条边,其中的 n − 1 n-1 n1条一开始已经定死了(注意题目给的都是有向图),即1和2之间有一条1到2的路,2和3之间有条2到3的路,以此类推一直到 n − 1 n-1 n1 n n n之间有条路 n − 1 n-1 n1 n n n的路(最后形成了一条链)。然后题目会再给你一个长度为n的数组,表示1~n这n个村庄与第n+1个村庄之间路的关系, a [ i ] a[i] a[i]若为0则表示可以从第 i i i个村庄走到第 n + 1 n+1 n+1个村庄,若为1则反过来,表示可以从第 n + 1 n+1 n+1个村庄走到第 i i i个村庄(都是有向的),让你输出一个路径,可以不重复的走过所有的村庄,若不存在则输出-1。

思路:

这里的路径是一定存在的,以下给定证明:

情况1:数组a全为0 如下图所示

那么一定存在一条1->2->3->4->…->(n-1)->n->n+1的路径,可以经过每个点,且仅走过一次。

情况2:数组a存在为1的情况 我们随意假定一个位置为1 如下图所示

在这里插入图片描述

我们从左到右遍历a,找到第一个为1的位置,设当前位置为pos,如果pos不是第1个位置的话,那么其前面所有的点,都有从它们到第 n + 1 n+1 n+1个点的路,如上图所示,那么我们一定可以从第一个点走到pos这个位置的前面,然后再走到点 n + 1 n+1 n+1,再从点 n + 1 n+1 n+1走到点pos,最后再从pos走到第 n n n个点。
若pos在第一个位置也没事,我们可以直接从点 n + 1 n+1 n+1走到1,再从1走到n即可。

代码:

#include<bits/stdc++.h>
//#pragma GCC optimize(2)
using namespace std; 
#define int long long
#define fi first
#define se second
#define endl '\n'
#define PII pair<int,int>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
const int N=1e6+5;
int h[N],e[N],nx[N],idx;
int k,T,t,n,m,ans,cnt;
int a[N];
bool vis[N];
priority_queue <int,vector<int>,greater<int> > q;
signed main()
{
        ios::sync_with_stdio(false);
         cin.tie(0),cout.tie(0);
        cin>>T;
        while(T--)
        {
                cin>>n;
                for(int i=1;i<=n;i++) cin>>a[i];
                int pos=-1;
                for(int i=1;i<=n;i++)
                {
                        if(a[i]==1)
                        {
                                pos=i;
                                break;
                        }
                }
                if(pos==-1)
                {
                        for(int i=1;i<=n+1;i++)
                                cout<<i<<" ";
                        cout<<endl;                
                }
                else
                {
                        for(int i=1;i<pos;i++)
                                cout<<i<<" ";
                        cout<<n+1<<" ";
                        for(int i=pos;i<=n;i++)
                                cout<<i<<" ";
                        cout<<endl;                
                }
        }

        return 0;
}

D1、Mocha and Diana (Easy Version)

题意:

给定n个点,以及k1和k2两个值,k1,k2分别代表在图一中连了k1条边,在图二中连了k2条边(无向图)。然后让你输出最多还能在图一和图二中连多少条边,不会让图变成有环图。注意,让你连的时候是图一图二同时进行操作的,也就是你若连图一的1和2两个点,那么图二中的1和2两个点也会连起来(前提是满足连起来之后不会形成环,若形成肯定不满足题目要求),但是题目一开始的连线操作是互不影响的,即连图一就是连图一,不会对图二造成任何影响。

思路:

我们注意到本题数据只有1000,并且只有一组数据,那么我们直接运用并查集即可,对于两个图分开来维护,然后最后 n 2 n^2 n2枚举还能连的边,若能连就连在一起即可。

代码:

#include<bits/stdc++.h>
//#pragma GCC optimize(2)
using namespace std; 
#define int long long
#define fi first
#define se second
#define endl '\n'
#define PII pair<int,int>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
const int N=1e6+5;
int h[N],e[N],nx[N],idx;
int k,T,t,n,m,ans,cnt;
int a[N],k1,k2,p1[N],p2[N];
bool vis[N];
PII res[N];
priority_queue <int,vector<int>,greater<int> > q;
int find1(int x)
{
        if(p1[x]!=x) p1[x]=find1(p1[x]);
        return p1[x];
}
int find2(int x)
{
        if(p2[x]!=x) p2[x]=find2(p2[x]);
        return p2[x];
}
signed main()
{
        ios::sync_with_stdio(false);
         cin.tie(0),cout.tie(0);
        cin>>n>>k1>>k2;
        for(int i=1;i<=n;i++) p1[i]=p2[i]=i;
        for(int i=1;i<=k1;i++)
        {
                int x,y;
                cin>>x>>y;
                p1[find1(x)]=find1(y);
        }
        for(int i=1;i<=k2;i++)
        {
                int x,y;
                cin>>x>>y;
                p2[find2(x)]=find2(y);
        }        
        for(int i=1;i<=n;i++)
                for(int j=i+1;j<=n;j++)
                {
                        if((find1(i)!=find1(j))&&(find2(i)!=find2(j)))
                        {
                                res[++cnt]={i,j};
                                p1[find1(i)]=find1(j);
                                p2[find2(i)]=find2(j);
                        }
                }        
        cout<<cnt<<endl;
        for(int i=1;i<=cnt;i++)
                cout<<res[i].fi<<" "<<res[i].se<<endl;
        return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值