A、Mocha and Math
题意:
给定一个长度为n的数组,你可以任选一个区间
[
l
,
r
]
[l,r]
[l,r]进行操作,对于这个区间的所有值
i
(
0
≤
i
≤
r
−
l
)
i (0≤i≤r−l)
i(0≤i≤r−l),将
a
l
+
i
a_{l+i}
al+i替换为
a
l
+
i
a_{l+i}
al+i&
a
r
−
i
a_{r−i}
ar−i。你可以进行无数次操作,让你求最后经过若干次操作后的数组中 最小的最大值是多少。
思路:
签到题,我们注意到可以 任选一个区间,进行无数次操作。并且每次进行&运算肯定会让&运算后的数小于等于原来的值,所以最小的最大值肯定就是把所有数进行&运算得到的数。因为其中的最大值想变小,肯定要去和其他比他更小的值进行&运算,前面提到了每次&之后,只会让原来的数变小或者不变,所以对所有数进行&运算一定会得到所求答案。
代码:
#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 2n−1条边,其中的 n − 1 n-1 n−1条一开始已经定死了(注意题目给的都是有向图),即1和2之间有一条1到2的路,2和3之间有条2到3的路,以此类推一直到 n − 1 n-1 n−1和 n n n之间有条路 n − 1 n-1 n−1到 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;
}