2020牛客寒假算法基础集训营5 题解

牛客训练营5

A 模板

题目很简单,要求的答案包括两部分:两个字符串长度的差num1和在短的字符串长度上,循环两者有num2个不同的字母,num=num1+num2;

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const  ll maxn=1e5+10;
char a[maxn];
char b[maxn];
int main()
{
    ll n,m;
    cin>>n>>m;
    cin>>a>>b;
    ll n1=sizeof(a);
    ll n2=sizeof(b);
    ll mi=0;
    mi=n1>n2?n2:n1;
    ll num=n1+n2-2*mi;
    for(int i=0;i<n1;i++){
                              if(a[i]!=b[i])
                              num++;
    }
    cout<<num<<endl;
    return 0;
}

B 牛牛战队的比赛地

这个题我一开始没想上,后来看了题解才知道可以用二分、三分的方法来解问题:

三分比较好想,只要函数有峰值,就可以用三分,在二分查找的基础上,在右区间(或左区间)再进行一次二分,这样的查找算法称为三分查找,也就是三分法:与二分法类似,先取整个区间的中间值mid;再取右侧区间的中间midmid,从而把区间分为三个小区间。 比较mid与midmid谁最靠近最值,只需要确定mid所在的函数值与midmid所在的函数值的大小。当最值为最小值时,mid与midmid中较小的那个自然更为靠近最值。最值为最大值时同理。

二分的方法是从0-500000,将mid=(l+r)/2,调整后check(mid):如果(a[i].x)^2 =mid ^ 2-a[i].y^2<0,说明当前的a[i].y的长度大于mid,说明mid取小了;然后再找当前点距离:首先用L、R来维护一段当前点x的范围,然后缩短这个范围,如果超过这个范围,说明最大距离变大了。如果在循环过程中,没有出现上述两种情况,舍弃右部。

//三分
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn=100005;
struct node{
    int x,y;
};
int n;
node a[maxn];
double check(double x)
{
    double max=0;
    for (int i=1;i<=n;i++)
    {
        double tmp=sqrt(a[i].y*a[i].y+(a[i].x-x)*(a[i].x-x));
        if (tmp>max) max=tmp;
    }
    return max;
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d%d",&a[i].x,&a[i].y);
    double l=-100000,r=100000;
    double mid,midm;    //三分的精髓,将选取的两个中间值进行比较,看看谁是
    for(int i=0;i<100;i++){
        mid=l+(r-l)/2; //最中间的
        midm=mid+(r-mid)/2;//右部中间值
        if(check(mid)>check(midm)) //极大值
            l=mid;
        else
            r=midm;
    }
    printf("%.4lf\n",check(mid));
    return 0;
}
//二分
#include<bits/stdc++.h>
using namespace std;
struct node{
               double x;
               double y;
};
node a[200005];
const double minn=1e-9;
int n;
bool check(double mid){
    double L=-1000000000,R=1000000000;
    for(int i=0;i<n;i++){
        if(mid*mid-a[i].y*a[i].y<0)
        {
            return 0;
        }
        double l=-sqrt((mid*mid-a[i].y*a[i].y))+a[i].x;
        double r=sqrt((mid*mid-a[i].y*a[i].y))+a[i].x;
        if(L>r||R<l){
            return 0;
        }
        L=max(l,L); R=min(r,R);
    }
    return 1;
}

int main(){
    double l,r,ans;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%lf %lf",&a[i].x,&a[i].y);
    }
    l=0,r=50000;
    while(l+minn<r){
        double mid=(l+r)/2;
        if(check(mid)){
            r=ans=mid;
        }
        else l=mid;
    }
    printf("%.4lf\n",ans);
    return 0;
}

D 牛牛与牛妹的约会

这道题难度低于上一道。有两种情况,判断一下:在最后一步之前(1单位之前,因为1的立方根是他本身),走闪现距离牛妹近,还是乖乖走单位一距离牛妹近:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const double pi=1.0/3.0;
ll n;
ll a,b;
int main(){
          scanf("%lld",&n);
          while(n--){
               scanf("%lld%lld",&a,&b);
               double ans=0;
               double nn=a;
               while(1){
                              double nu1,nu2;
                              nu1=abs(nn-b);
                              if(a>0)
                                    nu2=pow(nn,pi);
                              else
                                    nu2=-pow(-nn,pi);
                              if(abs(nu2-b)+1.0<nu1){ //距离大于1,闪现更快
                                             nn=nu2;ans+=1.0;
                              }
                              else{//按速度单位1/s走
                                             ans+=nu1;break;
                              }
               }
               printf("%.9f\n",ans);
          }
}

E enjoy the game

这一题,很显然,奇数肯定Bob赢,偶数一个一个的找,2找不到,4也找不到Bob必赢的方法,6可以,8不行,10可以,12可以,16不行…

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const  int maxn=1e3+10;
int main()
{
    ll n;
    cin>>n;
    ll i=2;
    while(i<=n){
               if(i==n){
                              printf("Alice\n");
                              return 0;
               }
               else i*=2;
    }
    printf("Bob\n");
    return 0;
}

F 碎碎念

这一题也是找规律,不难,找完规律后会发现是前缀和

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1000000007;
ll t,n;
ll a[100005];
ll b[100004];
int main(){
          cin>>t>>n;
          for(int i=0;i<t;i++){
               a[i]=1;
          }
          a[t]=2;
          for(int i=t+1;i<=100000;i++){
               a[i]=a[i-1]+a[i-t-1];
               a[i]%=mod;
          }
          b[0]=0;
          for(int i=1;i<=100000;i++){//前缀和
               b[i]=b[i-1]+a[i];
               b[i]%=mod;
          }
          while(n--){
               ll x,y;
               cin>>x>>y;
               ll sum=0;
               sum=(b[y]-b[x-1]+mod)%mod;
               cout<<sum<<endl;
          }
return 0;
}

H Hash

要找到比原来的字符串数字大的,又要前后的哈希值相等,分析前面的代码发现,所谓的哈希值,就是将字符串转换为26进制的数字,只要将前面的数字+mod,再转码为字符串就行了,关键在于,不要超过26*6-1.

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll mod;
char a[7];
char b[7];
int main(){
          while(scanf("%s%lld",a,&mod)!=EOF){
               ll num=0;
               for(int i=0;i<6;i++){
                              num=num*26+a[i]-'a';  //将字符型数组改成26进制的数字;
               }
               num+=mod; //保证找到字典序最小且大于s
               for(int i=5;i>=0;i--){  //转码,将26进制转换成字符型数组
                       b[i]=num%26+'a';
                       num/=26;
               }
               if(num)//所有字母>z,不满足题意
                              printf("-1\n");
               else
                              printf("%s\n",b);
          }
}

I I题是个签到题

有小坑,只要注意 100 100 40 30和100 100 100 40就可以了,因为他算上重复的。

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const  int maxn=1e3+10;
struct node{
               int lo;
               int num;
};
node a[maxn];
bool comparison(node a,node b){
    return a.num>=b.num;
}
int main()
{
    int m,n;
    cin>>m>>n;
    for(int i=0;i<m;i++){
               cin>>a[i].num;
               a[i].lo=i;
    }
    sort(a,a+m,comparison);
    /*for(int i=0;i<m;i++){
               printf("---%d:%d---",a[i].lo,a[i].num);
    }*/
    int mm=1,m1=0;
    for(int i=1;i<m-1;i++){
              mm++;
              if(mm>=3&&a[i].num!=a[i+1].num){
                              m1=i;
                              break;
               }
    }
    for(int i=0;i<=m1;i++){
               if(a[i].lo==8){
                              printf("Yes\n");
                             // printf("111");
                              return 0;
               }
    }
    //printf("\n");
    int ma=8*n;
    int aa=0;
    for(int i=0;i<m;i++){
              if(a[i].lo==8){
               aa=i;break;
              }
    }
   // printf("++%d:%d++\n",a[aa].lo,a[aa].num);
    int mb=a[aa].num*10;
    if(ma<=mb){
               printf("Yes\n");
               return 0;
    }
    printf("No\n");
    return 0;
}

J 牛牛战队的秀场

首先要求出,半径为r的正n边形的外切圆,其圆内的正n边形的边长的计算公式:2rsin(pi/n),然后找出ii到jj最短要走几条边:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PI 3.1415926
const  int maxn=1e3+10;
int main()
{
    int n;
    ll r,ii,jj;
    scanf("%d%lld%lld%lld",&n,&r,&ii,&jj);
    double ie;
    ie=2*r*sin(PI/(n*1.0));
    //printf("%.6f\n",ie);
    int nu=0;
    int maxnu=n/2;
    int in=max(ii,jj);
    int jn=min(ii,jj);
    //printf("%d %d",in,jn);
    if((in-jn)<=maxnu)
               nu=in-jn;
    else
               nu=(jn+n-in);
    double ans=ie*(nu*1.0);
    printf("%.6f\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值