2021牛客暑期多校训练营 4 题解
C LCS
题意:
LCS(si,sj)代表的是si,sj的最长公共部分的长度,不要求连续。
输入a,b,c,n;
LCS(s1,s2)=a; LCS(s2,s3)=b; LCS(s1,s3)=c;
n代表序列的长度。
问如果存在解,依次输出s1,s2,s3; 否则输出“NO”
思路:
进行构造。先求出a,b,c的最小值,最小值定义为x,
如果a+b-x>n或者a+c-x>n或者b+c-x>n都是无解状态,找不到满足的s1,s2,s3,直接输出"NO";
否者,进行构造,先都进行填入x个’a’,后s1,s2填入a-x个’b’,s2,s3填入b-x个’c’,s1,s3填入c-x个’d’;最后将s1,s2,s3剩下的空位用不同字符补齐即可。
AC代码
#include<bits/stdc++.h>
using namespace std;
int a,b,c,n;
string s1,s2,s3;
int main()
{
cin>>a>>b>>c>>n;
int x=min(a,min(b,c));
if(a+b-x>n||b+c-x>n||a+c-x>n)
{
cout<<"NO"<<endl;
}
else
{
for(int i=0;i<x;i++) s1+='a',s2+='a',s3+='a';
for(int i=0;i<a-x;i++) s1+='b',s2+='b';
for(int i=0;i<b-x;i++) s2+='c',s3+='c';
for(int i=0;i<c-x;i++) s1+='d',s3+='d';
while(s1.size()<n) s1+='e';
while(s2.size()<n) s2+='f';
while(s3.size()<n) s3+='g';
cout<<s1<<endl;
cout<<s2<<endl;
cout<<s3<<endl;
}return 0;
}
题意:
爱丽丝和鲍勃正在玩游戏。一开始,有一个无向图G 和 n节点。Alice和Bob轮流操作,Alice先上场。不能操作的玩家将输掉比赛。
每回合,玩家应该做以下操作之一:
1.删除一条边
2.删除一个连接的组件没有任何循环(不能含有环) 爱丽丝和鲍勃足够聪明,你需要找出谁会赢得这场比赛。
思路:
对于第一种操作,使得边数 - 1
对于第二种操作,使得点数 - x, 边数 -(x-1)
任何一种操作都会使得,边数 + 点数的和 减少一个奇数,所以,答案只与 n + m 的奇偶有关。
由于Alice先手,所以,如果 n + m 是奇数 ,Alice必赢,因为每一次的操作都是使得 边数 + 点数之和减少一个奇数,反之,如果为偶数则Bob赢
AC代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
if((n+m)%2==1) cout<<"Alice"<<endl;
else cout<<"Bob"<<endl;
return 0;
}
题意:
给出1- n个数的序列,每个数可以进行加0或者加1,使得序列中的逆序对最少,问最少有多少对逆序对?
思路:
要使得逆序对最少,如果 x 在 x+1 后面, 则 x 进行加1,后面的 x+1则不需要变化。这样的操作就能使得,逆序对减少1对。
所以,我们只需要求出满足上面条件的对数,将总逆序对数减去就是最少的逆序对。
得出数列利用归并排序得出逆序对数
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int num[N],b[N],c[N];
ll sum;
void gbsort(int l,int r,int a[])
{
int mid=(l+r)>>1;
if(l==r) return ;
else
{
gbsort(l,mid,a);
gbsort(mid+1,r,a);
}
int i=l,temp=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(a[i]>a[j])
{
sum+=mid+1-i;
b[temp++]=a[j++];
}
else
{
b[temp++]=a[i++];
}
}
while(i<=mid) b[temp++]=a[i++];
while(j<=r) b[temp++]=a[j++];
for(int i=l;i<=r;i++)
{
a[i]=b[i];
}
return ;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>c[i];
num[c[i]]=i;
}
gbsort(0,n-1,c);
for(int i=1;i<n;i++)
{
if(num[i]>num[i+1])
{
sum--;
i++;
}
}
cout<<sum<<endl;
return 0;
}
J Average
题意:
求至少x行,y列的矩阵和的最大平均值。
思路:
每个矩阵的平均值为:
又由于w[i][j]=a[i]+b[j]得子矩阵的和就等于
平均值就为
所以其实答案是分别对 a 和 b 对应的区间求个平均值然后加起来
问题转化成了 : 找 a 的一个长度至少为 x 的平均值最大的子区间和 b 的一个长度至少为 y 的平均值最大的子区间.由于题目给的大小为1e5我们可以用二分来找最大值。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,x,y;
int a[maxn];
double b[maxn];
double fun(int k,int d)
{
double l=0.0,r=1e5;
for(int i=1;i<=k;i++) cin>>a[i];
while(r-l>1e-8) //10^-8
{
double mid=(l+r)/2.0,sum,t=0.0;
for(int i=1;i<=d;i++) b[i]=b[i-1]+a[i]-mid;
sum=b[d];
for(int i=d+1;i<=k;i++)
{
t=min(t,b[i-d]);
b[i]=b[i-1]+a[i]-mid;
sum=max(sum,b[i]-t);
}
if(sum>0) l=mid;
else r=mid;
} return r;
}
int main()
{
cin>>n>>m>>x>>y;
printf("%.10lf\n",fun(n,x)+fun(m,y));
return 0;
}
如果觉得写的不错,点个赞吧^ - ^