1. 程式人生 > >2018-2019賽季多校聯合新生訓練賽第四場題解與補題

2018-2019賽季多校聯合新生訓練賽第四場題解與補題

這一場比賽我是在宿舍裡打的,環境非常的惡劣(噓) 因為舍友一直在說話啥的 不過這也是沒辦法的事,畢竟是週末嘛~ 上來第一題就給我嚇破膽了 ,嚇得我拿了一個本子在那個地方瘋狂計算,把每種情況都寫出來以後才敢開始coding 後來提交發現已經好多人a了這道題,挺不應該的 還有一個要注意的是,千萬不要上來就看最後一題!!因為我以前覺得最後一題肯定是水題,很多次比賽都是這樣的,但是這次卡了很長時間!所以要引以為鑑哦! 下面開始啦:

問題 A: 數一數

題目描述

星期天早上,小明開始做數學家庭作業。因為小明成績很優異,覺得題目太簡單了,思考出道難點的數學題去學校考考同學,他注意到:數學書的第10頁和第11頁在同一張紙上,但第11頁和第12頁不在同一張紙上。
哈哈,題目有了,請問數學書的第x頁到第y頁共有多少張紙呢?
例如:該書的第81頁到第92頁,共有7張紙。

輸入

一行兩個數x、y如題所述,用空格隔開。

輸出

一個數,表示紙張數。

樣例輸入
複製樣例資料 81 92

樣例輸出
7

提示

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

注意這裡要用long int 型別 或者是long long int 不然可能執行錯誤 這裡我分了幾種情況,全部寫在本子上發現只有一種情況
和其他的不一樣,那就是第一個數是奇數而第二個數是偶數的時候,先加上2 然後(b-a)/2 這也算是個模擬題把! 就是不明白為
啥我模擬了這麼長時間的東西別人幾十秒就能做出來...心態崩了 上程式碼:
#include<bits/stdc++.h>
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<bits/stdc++.h>
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<<sum;
}*/

這一次讓我們來開兩個陣列,一個是結構體陣列,一個是陣列,一個來存id和數量,一個存一下每一次的數量,然後用a[i].b(數量)
來表示b[i]的i下標,(因為此前把每次的數量都存到了b[i]裡面,當a[i].id==1該刪除的時候,就用sum減去id=1的時候對應的乘
客的數量就行了,這時候的a[i].b就相當於第幾組)這樣就解決了無法正確的刪除在第一次出現1之前的數的問題了!!!
程式碼:
#include<bits/stdc++.h>
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<bits/stdc++.h>
using namespace std;
int a[200000];
int main() {
  int n,k;
  cin>>n>>k;
  for(int i=0;i<n;i++)
  cin>>a[i];
  int sum1=0,sum2=0;
  for(int i=0;i<n;i++) {
    if(a[i]>k)
    break;
    else
    sum1++;
  }
  for(int i=n-1;i>=0;i--) {
    if(a[i]>k)
    break;
    else
    sum2++;
  }
  if(sum1>=sum2)
  cout<<sum1;
  else
  cout<<sum2;
}*/

後來自己試了幾個樣例,發現如果中間出現最大的話就沒轍了..於是就邊找邊加,邊加變比,找到最大的就更改一下最大值,這一樣以
後就順利ac啦~  當然要注意maxn賦初值要附一個負數 不然的話生成隨機數可能比你所有情況都大! 這樣就沒辦法起到效果了程式碼:
#include<bits/stdc++.h>
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<bits/stdc++.h>
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

問題 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<bits/stdc++.h>
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<bits/stdc++.h>
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<bits/stdc++.h>
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<b<…<z)誰將獲得勝利。具體規則可參考樣例。雖然現在小李的牌已經很好了,但是你能不能幫他快速算出起始位置,使得他能夠派出最強陣容。

輸入

第一行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!!! 祝大家都能更上一層樓 取得好成績!~