牛客寒假训练营1(B-F-I-J)部分题解

训练营的比赛已经开了3场了,也已经过年了,博客好像好久都没有更新过了,补一场的吧。
虽然说是基础训练营,但还是挺难的,感觉…
好了,不说了,开始吧。
B-括号
在这里插入图片描述
题意:就是让你找对应k的括号排列。正好有k个括号排列。
思路:这个题的数据范围比较大,如果按照它样例给出的办法,会超时。这个题当时也卡了很久,我的小朋友试出了办法,还是我太菜了。这个题,要是想到的话,就很快,想不到的话,就会绕弯。
它是左右()的数量相等的话,假如是n个的话,就按照n的平方的速度增加,所以我们先看比k小的最大平方数。然后看k-平方数差几个,然后从右边或者左边都行,假如从右边来说,就从右向左来找(,进行补齐。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
int judge(ll x)
{
    if(x == 1)
        return 0;
    else if(x ==2)
        return 1 ;
    else if(x==3)
        return 1;
    else if(x%6!=1&&x%6!=5)
        return 0 ;
    int t =sqrt(x);
    for(int i= 5; i <=t; i=i+6 )
        if(x%i== 0||x%(i+2)==0)
            return 0;
    return 1 ;
}

int main ()
{
    cin>>n;
    if(n==0)
        cout<<")("<<endl;//0的时候,不能输出空串
    else if(n==1)
        cout<<"()"<<endl;
    else if(n==2)
        cout<<"())"<<endl;
    else if(n==3)
        cout<<"()()"<<endl;
    else
    {
        int p=sqrt(n);//找最大的出来的平方根
        int q=n-p*p;//差的数量
        int xx=q/p;//差的数量用几个p来补齐
        int w=0;
        if(q%p!=0)//不能整除的话,就单的一边来补齐
        {
            w=q%p;
        }
        for(int i=1;i<=p+xx;i++)//左边的话就是p+不能补齐的
        {
            cout<<'(';
        }
        for(int i=1;i<=p;i++)//单出来的一侧,从后向前
        {
            if(i==p-w+1){
                cout<<'(';
            }
            cout<<')';
        }
        cout<<endl;
    }
    return 0;
}

F-对答案一时爽
在这里插入图片描述
题意:找出得分的最大值
思路:签到题,就是让一个人对就是最大的
代码:

#include<bits/stdc++.h>
using namespace std;
const int N=110;
char a[N],b[N];
int main ()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int n;cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(int i=1;i<=n;i++)
    {
        cin>>b[i];
    }
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==b[i])
        {
            sum++;
        }
    }
    cout<<n+sum<<" "<<0<<endl;
    return 0;
}

I-限制不互素对的排列
在这里插入图片描述
题意:构造长度为n的序列,正好有k对相邻的数gcd>1。
思路:gcd>1,就是相邻的不能是素数,因为1~n的数,只能用一次,偶数不可能是素数,所以我们可以利用偶数来排列,3和6,虽然不是偶数,但是按照 6 3 来排列的话,也可以达成一对,因为6是偶数,3是素数,所以要按照6 3来排列。到达k对之后,剩下的可以按照从1开始,没有利用的数相邻排列就可以了,因为剩下的都是素数了。但如果n小于6的话,n/2就是偶数的个数等于n的话,就无法构造成功。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
bool vis[N];
int a[N];
int main ()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int n,k;cin>>n>>k;
    if(n<6&&k==n/2)//特判
    {
        cout<<-1<<endl;
    }
    else
    {
        int cnt=0;
        for(int i=2;i<=n;i=i+2)
        {
            if(i!=6)
               a[++cnt]=i;//不算6,把小于n的偶数存进数组
        }
        a[++cnt]=6;a[++cnt]=3;//将6 3分别按顺序存进数组
        for(int i=1;i<=k+1;i++)
        {
            cout<<a[i]<<" ";
            vis[a[i]]=1;/输出k对,就是到k+1个数字,然后标记一下
        }
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==0)
                cout<<i<<" ";//将剩下的数字排列输出,因为相邻的数字gcd一定=1
        }
        cout<<endl;
    }
    return 0;
}

J-一群小青蛙呱蹦呱蹦呱
在这里插入图片描述
在这里插入图片描述
题意:就是有一个以素数为公差的等比数列,然后都从1开始,进行标记,没有被标记过的数字的lcm是多少?
思路:这题是数论,数论渣渣,看了好几个题解,理解个大概吧,试一试吧,吃掉了所有所有的素数的倍数,剩下的就是含有大于两个质因子的数了,所以求lcm,其实就是求这些质因子的最大次幂,让幂次最大的话,如果是2的话,那么最大的那个数一定是2^k * 3=n,所以k这个最大的幂次就是log2^(n/3),为什么呢,因为每次最大就是让这个数利用2最多次,然后左边最大就是右边最大,那么最大就是n了,那么素数是从2 3 5开始的,最大的数就是幂次最多,然后*最小的数,如果>2的话,就是当前数字pi^k * 2=n,所以k=logpi^(n/2)。其实换句话来说,就是 让pi^k 最大,就是k最大,等式右边就是n/一个数,你得让那个数尽可能的小,所以是2 或者 3。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=8e7+5;
const ll mod=1e9+7;
int p[N/8];
bool vis[N];
int cnt=0;
int n;
ll ksm(int a,int b){//快速幂
	ll ans=1,t=a;
	while(b)
	{
		if(b&1)
			ans=ans*t%mod;
		t=t*t%mod;
		b>>=1;
	}
	return ans;
}
ll calc(int x){//求log的过程
	if (x==2)//有点细节,就是得用floor来计算
		return ksm(2,floor(log(1.0*n/3)/log(1.0*2)));
	return ksm(x,floor(log(1.0*n/2)/log(1.0*x)));
}
int main ()
{
    //ios::sync_with_stdio(false);
    cin>>n;
    ll ans=1;
    memset(vis,1,sizeof vis);
    for(int i=2;i<=n/2;i++)//范围太大,n/2的范围就够用了
    {
       // cout<<ans<<endl;
        if(vis[i])
        {
            p[cnt++]=i;//没被标记,就是素数
           // cout<<ans<<endl;
            ans=(ans*calc(i))%mod;
            //cout<<ans<<endl;
        }
        for(int j=0;j<cnt&&i*p[j]<=n/2;j++)
        {
            vis[i*p[j]]=0;//线性筛
            if(i%p[j]==0)
                break;
        }
        //cout<<ans<<endl;
    }
    if(ans==1)
        cout<<"empty"<<endl;//判空
    else
        cout<<ans<<endl;//答案
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值