2018-2019赛季多校联合新生训练赛第四场题解与补题(中石油)

这一场比赛我是在宿舍里打的,环境非常的恶劣(嘘) 因为舍友一直在说话啥的 不过这也是没办法的事,毕竟是周末嘛~ 上来第一题就给我吓破胆了 ,吓得我拿了一个本子在那个地方疯狂计算,把每种情况都写出来以后才敢开始coding 后来提交发现已经好多人a了这道题,挺不应该的 还有一个要注意的是,千万不要上来就看最后一题!!因为我以前觉得最后一题肯定是水题,很多次比赛都是这样的,但是这次卡了很长时间!所以要引以为鉴哦! 下面开始啦:

问题 A: 数一数

题目描述

星期天早上,小明开始做数学家庭作业。因为小明成绩很优异,觉得题目太简单了,思考出道难点的数学题去学校考考同学,他注意到:数学书的第10页和第11页在同一张纸上,但第11页和第12页不在同一张纸上。
哈哈,题目有了,请问数学书的第x页到第y页共有多少张纸呢?
例如:该书的第81页到第92页,共有7张纸。

输入

一行两个数x、y如题所述,用空格隔开。

输出

一个数,表示纸张数。

样例输入
复制样例数据 81 92

样例输出
7

提示

50%:0 100%:1<=x,y<=longint;0

注意这里要用long int 类型 或者是long long int 不然可能运行错误 这里我分了几种情况,全部写在本子上发现只有一种情况
和其他的不一样,那就是第一个数是奇数而第二个数是偶数的时候,先加上2 然后(b-a)/2 这也算是个模拟题把! 就是不明白为
啥我模拟了这么长时间的东西别人几十秒就能做出来...心态崩了 上代码:
#include
using namespace std;
int main() {
  long long int a,b;
  cin>>a>>b;
  if(a%2==0) {
    if(b%2==0) {
    cout<<(b-a)/2+1;
    return 0;
  }
  else if(b%2!=0) {
    cout<<(b-a)/2+1;
    return 0;
    }
  }
  if(a%2!=0) {
    if(b%2!=0) {
      cout<<(b-a)/2+1;
      return 0;
    }
    else if(b%2==0) {
      cout<<2+(b-a)/2;
      return 0;
    }
  }
}

问题 B: 博物馆

题目描述

从前,有一个偌大的博物馆,每天都会有数以万计的人们来参观,欣赏这里的艺术作品。这一天,博物馆来了N批人,第i批人有Ai个人以及一个导游组成,他们依次到达,但同时也有一些批次的人离开,由于人次太多,博物馆的管理人员递给你一些人数表,就请你来统计一下剩下多少人。

输入

第一行是个整数N,接下来N行。每行两个数,第一个数X,如果X=0则后面接一个数Ai,表示来了Ai个人;如果X=1,那么接下来就有一个数Y,表示来的人中的第Y批离开了。

输出

一个数,表示剩下多少人。

样例输入
复制样例数据 6
0 5
0 6
1 1
0 7
0 8
1 3

样例输出
16

提示

有四批人,每批人要加上一位导游,分别是6,7,8,9人,离开的是第1和3批,即走了6+8=14人,剩7+9=16人。

对于30%的数据,1≤N≤100,1≤Ai≤1000;
对于100%的数据,1≤N≤1000000,1≤Ai≤1000000。
保证:X只为0或1,Y一定符合要求。

这破题我做了一个半小时多...等我舍友催我出去跑步之后我才做出来了 感觉思路还是不是很清楚,一盆浆糊一盆粥的感觉
先说一下我刚开始的想法8 
 刚开始我想的是开一个结构体,里面有两个变量,上面的如果第一个是0的话++没什么好说的,主要是下面计算sum的时候
 我想的是先定一个s 来统计第一个id 是1的个数,然后因为1,下一批人的实际批次和他们的下标就不相等了,然后用s统计
 的话就可以解决这个问题,但是交了以后WA了  才发现当小于第一次出现1的时候结果是错的,如果加上一句if(a[i].id<
 第一次出现1的地方s就不用加上了),但是我想不出来这种方法怎么写啊。。。于是只能把之前的全部推翻 这是非常痛苦的
 毕竟这一个思路打了不下十遍了,全部都错,于是只能再开一次数组,这次开两个。

下面是错误代码:

/*#include
using namespace std;
struct node {
  int id;
  int b;
}a[100010];
int main() {
  int n;
  cin>>n;
  for(int i=1;i<=n;i++) {
    cin>>a[i].id>>a[i].b;
    if(a[i].id==0)
    a[i].b++;
  }
  int sum=0;
  for(int i=1;i<=n;i++) {
    if(a[i].id==0)
    sum+=a[i].b;
  }
  int s=0;
  for(int i=1;i<=n;i++) {
    if(a[i].id==1) {
      sum-=a[a[i].b+s].b;
      s++;
    }
  }
  cout<

这一次让我们来开两个数组,一个是结构体数组,一个是数组,一个来存id和数量,一个存一下每一次的数量,然后用a[i].b(数量)
来表示b[i]的i下标,(因为此前把每次的数量都存到了b[i]里面,当a[i].id==1该删除的时候,就用sum减去id=1的时候对应的乘
客的数量就行了,这时候的a[i].b就相当于第几组)这样就解决了无法正确的删除在第一次出现1之前的数的问题了!!!
代码:
#include
using namespace std;
struct node {
  int a;
  int b;
}a[1000010];
int b[1000010];
int main() {
  int n;
  cin>>n;
  int k=1;
  int sum=0;
  for(int i=1;i<=n;i++) {
    cin>>a[i].a>>a[i].b;
    if(a[i].a==0) {
      a[i].b=a[i].b+1;
      b[k]=a[i].b;
      k++;
      sum+=a[i].b;
    }
    else {
        sum-=b[a[i].b];
    }
  }
  cout<<sum;
}

问题 C: 旅游

题目描述

Lanlan的好朋友Qiqi来到了东莞,她决定带Qiqi去东莞的名胜景区旅游,以此增进友谊。但Qiqi不喜欢去拥挤度大于k的景点,而且旅游的时间不能是断开的。Lanlan现在知道了明天n个连续时间景区的拥挤度,她想知道她最多能陪Qiqi旅游多久。

输入

第一行两个整数n,k。
第二行有n个整数表示每个时间的拥挤程度(数值小于1000)。

输出

一个整数表示Lanlan最多能陪Qiqi的时间。

样例输入
复制样例数据 20 2
1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

样例输出
16

提示

60%的数据 N<=1000
100%的数据 N<=100000

这题上来我就错了两次,第一次是因为我是倒着排序,然后找到以后 发现和样例一样,于是就提交了,那时候因为别的题都做不对,
一心慌就疯狂的想提交,于是第二次我抱着少考虑情况的心理改了一下,让他从前面遍历一遍,从后面再遍历一遍,全部找到以后
拿两个比较一下 ,交了一下发现还是错了:

错误代码:

/*#include
using namespace std;
int a[200000];
int main() {
  int n,k;
  cin>>n>>k;
  for(int i=0;i>a[i];
  int sum1=0,sum2=0;
  for(int i=0;ik)
    break;
    else
    sum1++;
  }
  for(int i=n-1;i>=0;i--) {
    if(a[i]>k)
    break;
    else
    sum2++;
  }
  if(sum1>=sum2)
  cout<

后来自己试了几个样例,发现如果中间出现最大的话就没辙了..于是就边找边加,边加变比,找到最大的就更改一下最大值,这一样以
后就顺利ac啦~  当然要注意maxn赋初值要附一个负数 不然的话生成随机数可能比你所有情况都大! 这样就没办法起到效果了代码:
#include
using namespace std;
int a[100010];
int main() {
  int maxn=-1;
  int n,k;
  cin>>n>>k;
  for(int i=0;i<n;i++) {
    cin>>a[i];
  }
  int sum=0;
  for(int i=0;i<n;i++) {
    if(a[i]<=k)
    sum++;
    else
    sum=0;
    maxn=max(maxn,sum);
  }
  cout<<maxn;
}

问题 D: 17倍

题目描述

学习程序设计的Lanlan记得老师给她布置的第一个任务是:输入一个数N,然后输出17*N的值。当然这个任务非常简单,经过一段时间的学习,兰兰有了一些的进步,老师又布置了一个类似的任务,只是变更了一个条件,输入的N是一个二进制数,输出的值也要是二进制表示的。
现在请帮助Lanlan完成这个任务。

输入

一个二进制表示的数N。

输出

二进制表示的17*N。

样例输入
复制样例数据 10110111

样例输出
110000100111

提示

10110111相当于十进制的183,于是183*17=3111,二进制形式是110000100111。

30%的数据N的位数小于25位
50%的数据N的位数小于50位
100%的数据N的位数小于1000位

这题我写了一个二进制转换为十进制的,然后又写了十进制转成二进制的,中间*了一次17,结果没问题我就提交了,结果
一看数据量,发现N的位数可能到1000位 瞬间不知道怎么做了。。。先把我位数小的方法贴上吧~
#include
using namespace std;
int main() {
  string a;
  long long int sum=0;
  cin>>a;
  int l=a.size();
  for(int i=0;i<l;i++) {
    if(a[i]-'0'==1)
    sum+=pow(2,l-i-1);
  }
  cout<<sum<<endl;
  sum*=17;
  long long int c,d;
  d=0;
     long long int b[2000];
     c=sum;
     while(c)
     {
      b[d]=c%2;
      c/=2;
      d++;
     }
     for(c=d-1;c>=0;c--)
      cout<<b[c];
  }

long long 都用上了还是不给面子啊! 听说java自带大数运算 回来试试23333

这是?大佬的python写法

import math
print(bin(int(input(),2)*17)[2:])

问题 E: 约数国王

题目描述

数学的王国里,有一些约数国王……约数国王的定义是这样的:一个大于1的整数n,如果它约数的个数比1~n-1的每个整数的约数的个数都要多,那么我们就称它为约数国王。聪明的小明在奥数书上认识了它们,于是产生了一个问题:他想知道L到R之间一共有多少个约数国王?它们分别又是谁?

输入

只有一行,包含一个l,一个r,表示小明想知道的范围。

输出

只有一行,第一个数h,表示l~r内一共有多少个约数国王,接下来h个从小到大的数(为了防止国王们打架,你需要按顺序输出。),表示约数国王分别是谁。

样例输入
复制样例数据 1 100

样例输出
8 2 4 6 12 24 36 48 60

提示

对于30%的数据,1<=l<=r<=200000。
对于50%的数据,1<=l<=r<=500000。
对于70%的数据,保证最大的约数国王的约数的个数不大于1000。
对于100%的数据,1<=l<=r, 并且保证l,r在64位整型以内,最大的约数国王的约数的个数不大于200000。

此处无声胜有声(待解决2333)

问题 F: 移动石子

题目描述

期待已久的“清明”假期终于到了。清明节是中华民族几千年来留下的优良传统,它有利于弘扬孝道亲情,唤醒家庭共同记忆,促进家庭成员乃至民族的凝聚力和认同感。
小学生卡卡西非常高兴,因为清明前后正是踏青的好时光,他终于可以和小伙伴们一起出去踏青了!然而,天公不作美,假期的第一天就下起了雨,卡卡西只能放弃出游计划,待在家里。
期间,无聊的卡卡西和小伙伴玩了一个博弈游戏:
在一个给定的 n×n 的棋盘上,有一个石头被放在棋盘的左上角。他们轮流移动石头。每一回合,每个人只能把石头向上,下,左,右四个方向移动一格,并且要求移动到的格子之前不能被访问过。谁不能移动石头了就算输。假如小卡卡西先移动石头,而且两人都以最优策略走步,问最后谁能赢?

输入

输入有多组数据。
输入第一行包含一个整数n,表示棋盘的规模。
当输入n为0时,表示输入结束。

输出

对于每组数据,如果小卡卡西最后能赢,则输出“Kakashi”,否则输出“Lost”,每一组答案独占一行。

样例输入
复制样例数据 2
0

样例输出
Kakashi

提示

对于20%的数据,保证1<=n<=10;
对于40%的数据,保证1<=n<=1000;
对于所有的数据,保证1<=n<=10000。

这题就是队里马老板经常说的“被吓破胆了”的典型例子 刚开始我看到这个都不知道咋办了,但是一想马老板老是说 不能被题目
吓破胆了啊,于是就尝试性的做了一下,没想到直接找到了规律,发现只要是奇数的话都是输,如果是偶数的话就是卡卡西赢了
我也不知道为啥当时要特判一下n==1的情况,可能一朝被蛇咬十年怕井绳把  代码:
#include
using namespace std;
int main() {
  int n;
  while(cin>>n&&n) {
    if(n==1) {
      cout<<"Lost\n";
      continue;
    }
    else if(n%2==0) {
      cout<<"Kakashi\n";
      continue;
    }
    else if(n%2!=0) {
      cout<<"Lost\n";
      continue;
    }
  }
}

问题 G: 列车线路

题目描述

终于,卡卡西来到了一个叫“比特兰”的国家,“比特兰”是个很发达的国家,有着非常高科技的列车,和非常复杂的列车线路。具体来说,从理论上,我们可以假设这个国家的高科技列车可以不消耗时间的从A地瞬间转移到B地。同时,铁路线路复杂到,每对城市之间都有列车连接。但是不幸的是,由于这种列车运行需要很多维护工作,所以每天只能发出一次。从i到j的列车(i≠j)会在ti,j时间发出(保证ti,j两两不同)。
如果有一条路径链接A和B两个城市,并且满足路径上的每⼀条边的发车时间单调递增(也就是说经过的每段铁路的发出时间都要大于上一段的,因为我们需要从上一段铁路换乘下一段铁路)。现在“比特兰”的铁路局想要知道,一天之内,对于每一对i和j,如果想要从i到达j,最早多早能到达呢?

输入

第一行一个整数n。
接下来n行,每行n个整数。表示ti,j。(i=j时保证ti,j=0,不算一条线路)

输出

n行,每行n个整数ansi,j,表示从i到j最早的到达时间。(i=j的时候ansi,j=0)

样例输入
复制样例数据 3
0 4 5
2 0 3
1 6 0

样例输出
0 4 5
2 0 3
1 4 0

提示

对于20%的数据,n<=10
对于40%的数据,n<=20
对于60%的数据,n<=50
对于100%的数据,n<=500,ti,j<=109

此处无声胜有声(待解决2333)

问题 H: 搭积木

题目描述

积木对于大家来说应该很熟悉,我们可以用积木搭建出各种各样的模型,不同的人搭建出来的模型也会不一样。这不,小卡卡西正在和一群小伙伴玩积木呢!
铁人老师看见小朋友们在玩积木,就给大家出了一个难题:
给定一些方形的积木,积木的三维尺寸分别为正整数Xi,Yi,Zi,每一种积木
都可以认为是无限多个。并且在搭建过程中约定如下条件:
1.搭建的模型每一层只能用一个积木;
2.模型的每一层的积木的底面必须小于它的下层,当然积木的底面可以是6个面中的任一个。
那么要如何搭建,才能使模型最高呢?

输入

第一行一个数N,表示不同积木的种数(N<=1000)
以下N行,每一行描述一种积木。
Xi、Yi、Zi(<=100)分别为三边的长度

输出

一行一个数M,表示在给定的条件下能搭建的最高模型的高度。

样例输入
复制样例数据 1
10 20 30

样例输出
40

此处有无声胜有声(待解决2333)

问题 I: 幸运数字III

题目描述

小李非常喜欢数字4和7,看到一个数字他就想快速计算出因子里面分别有几个4和7,但是智商捉急的他总是要算很久,喜欢编程的你能够帮助他吗?

输入

第一行一个整数n(3<=n<=2^60),表示给定的数字。

输出

两个用空格隔开的数字,分别表示给定数字的因子中4和7的个数。

样例输入
复制样例数据 112

样例输出
2 1

提示

112=447

这题算是一道水题,直接让一个数等于输入的数,然后while循环就行了,注意循环的条件不是while(n)而是n!=1 或者怕错的话
就学我写个while(1)然后在循环里面写条件退出就行了 代码:
#include
using namespace std;
int main() {
  long long int n;
  cin>>n;
  int a=0,b=0;
  while(1) {
    if(n%4==0) {
      a++;
      n/=4;
    }
    else if(n%7==0) {
      b++;
      n/=7;
    }
    else {
        cout<<a<<" "<<b;
        return 0;
    }
  }
}

问题 J: 英雄卡

题目描述

小李非常迷恋收集各种干脆面里面的英雄卡,为此他曾经连续一个月都只吃干脆面这一种零食,但是有些稀有英雄卡真的是太难收集到了。后来某商场搞了一次英雄卡兑换活动,只要你有三张编号连续的英雄卡,你就可以换任意编号的英雄卡。小李想知道他最多可以换到几张英雄卡(新换来的英雄卡不可以再次兑换)。

输入

第一行,共一个整数n(1<=n<=10000),表示小李拥有的英雄卡数。
第二行,共n个空格隔开的数字ai(1<=ai<=100000),表示英雄卡的编号。

输出

输出仅有一行,共1个整数,表示小李最多可以换到的英雄卡。

样例输入
复制样例数据 6
3 1 2 4 4 5

样例输出
1

提示

1 2 3三张编号连续,可以换一张,换完后剩下4 4 5,不符合兑换规则,无法继续兑换。

这题的思路是先开桶 然后输入x a[x]++,下面判断,如果他们三个连着的都大于1 即三个编号连续的数字的数量都大于1 这样的
话就找一下他们之中最小的那个,加上之后再让他们减去最小的,之后再计算(而不是直接赋值0,)原因:不知道他们下面是否
还能组成一套卡牌 举个例子把: 1234 各有2 3 4 5 张  先减去2以后能换两次,这样的话234还能换一次 ,如果直接赋值成0
的话,就无法找到这种情况,导致最后情况数量变少了,这里需要注意一下哦!最后全部加上就完事啦~ 代码:

这里我试了一下cmp的方法排序,发现我并不会三个参数的排序。于是只好自定义一个int类型的函数
然后return一个值 就是最小值

#include
using namespace std;
int a[100010];
int find_min(int a,int b,int c) {
  if(a<=b&&b<=c&&a<=c||a<=c&&c<=b&&a<=b)
  return a;
  else if(b<=a&&b<=c&&a<=c||b<=c&&b<=a&&c<=a)
  return b;
  else if(c<=a&&c<=b&&a<=b||c<=a&&c<=b&&b<=a)
  return c;
}
int main() {
  int n,x;
  cin>>n;
  for(int i=0;i<n;i++) {
    cin>>x;
    a[x]++;
  }
  int sum=0;
  for(int i=1;i<=100000;i++) {
    if(a[i]>=1&&a[i+1]>=1&&a[i+2]>=1) {
      x=find_min(a[i],a[i+1],a[i+2]);
      sum+=x;
      a[i]-=x;
      a[i+1]-=x;
      a[i+2]-=x;
    }
  }
  cout<<sum;
}

问题 K: 最强阵容

题目描述

拿着新换来的英雄卡,小李满心欢喜的准备和同学们PK一下。
他们的游戏规则非常简单,双方把自己的牌绕成一圈,然后指定一个起点,从该张牌开始顺时针方向往后取,谁取出的字符串字典序更小(从左到右开始比较,碰到第一个不一样的字符进行比较,比较规则为a

输入

第一行n(1<=n<=30000),表示共有n张牌。
第二行共n个用一个空格隔开的小写字母,表示给定的一圈牌起始序列。

输出

仅一个整数,能获得最小字典序字符串的起点位置。如果有多个位置开始的字符串一样,则输出最小的那个位置,且第一个位置从1开始。

样例输入
复制样例数据 4
b c a b

样例输出
3

提示

四个位置取出的字符串分别为bcab,cabb,abbc,bbca,显然最小位置是3。

此处无声胜有声(待解决2333)

问题 L: 最强素数

题目描述

小李在你帮助之下轻松战胜了他的同学们,于是满怀恶意的同学出了一个题目来为难小李,作为小李神一样的队友,你又要出力了。
素数41能写成连续6个素数之和:41=2+3+5+7+11+13。
现在要求n以内的素数中,能表示为最多连续素数之和的那个数,如果有多个答案,请输出最大的那个素数。

输入

仅一行,一个整数n(1<=n<=1000000)。

输出

输出就一个整数,为所求的能表示为最多连续素数和的那个素数。

样例输入
复制样例数据 100

样例输出
41

提示

41=2+3+5+7+11+13

此处无声胜有声(待解决2333)

大概就是这样了 最后的结果是第42名(铜牌第一名)跟我新生赛排名一样2333
还有几个不会的今天学习以后就会更新啦 如果借鉴别人的思路我都会注上名字的~~
然后就是 fighting!!! 祝大家都能更上一层楼 取得好成绩!~

你可能感兴趣的:(周赛/中石油题解)