2021牛客暑期多校训练营 4 题解

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;
}

F Just a joke

题意:
爱丽丝和鲍勃正在玩游戏。一开始,有一个无向图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;
}

I Inverse Pair

题意:
给出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;
}

如果觉得写的不错,点个赞吧^ - ^

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

稚皓君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值