2018年第九屆藍橋杯B組題解



題目連接:第九屆藍橋杯試題 C\JAVA


第一題:第幾天


答案:125

很簡單的數一數就好了,但是我當時可能沒帶腦子,按2010年算的124天。


第二題:明碼

答案:387420489

按着題目把這些數轉換成8字節的二進制數就可以了,負數的二進制是補碼。可以自己寫個函數實現一下,實際效果圖:



還可以用bitset,將一個數轉換成8位的二進制數,不足用0補位,然后再將bitset數轉換成string然后輸出。

實現代碼:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n,m;
    string str1,str2;
    while(cin>>n>>m){
        bitset<8> b(n);
        str1 = b.to_string();
        int len1 = str1.length();
        for(int i=0;i<len1;i++){
          if(str1[i] == '0')printf(" ");
          else printf("*");
        }
        bitset<8> c(m);
        str2 = c.to_string();
        int len2 = str2.length();
        for(int i=0;i<len2;i++){
          if(str2[i] == '0')printf(" ");
          else printf("*");
        }
        printf("\n");
    }
    return 0;
}


第三題:乘積尾零


答案:31

之前計蒜客的第五次模擬賽有道題是求n!末尾有多少個0,那道題就是求1-n的因子里有多少個5。因為想要出現0,只有當有2和5出現的時候,才會出現0,所以我們只需要求出這么多數,能分解出多少個2和5,小的那個數就是結果。

實現代碼:

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
  int n;
  int num1 = 0;
  int num2 = 0;
  while(cin>>n){
    while(1){
      if(n % 2 == 0){
        n /= 2;
        num1++;
      }
       else if(n % 5 == 0){
        n /= 5;
        num2++;
      }
      else {
        break;
      }
    }
  }
  printf("%d\n",num1>num2?num2:num1);
  return 0;
}

第四題:測試次數


答案:19

這是一道谷歌的面試題,應該用dp而不是二分。谷歌面試題:丟雞蛋

第五題:快速排序


答案:a,i+1,r,k-(i-l+1)

雖然填寫別的答案也能過樣例,但是這道題的要求是時間復雜度為O(n)。

第六題:遞增三元組


可以先對三個數組排序,然后遍歷數組b,查找a數組中有多少個小於b[i]的,c數組中有多少個大於b[i]的。

還有就是可以直接線性求出答案,即a[x]表示第一個序列中,有多少個數字等於x,b[],c[]同理那么有:
for i = 100000 → 0
c[i] = c[i]+c[i+1]
b[i] = b[i]*c[i+1]+b[i+1]
a[i] = a[i]*b[i+1]+a[i+1]

最后a[0]就是答案

二分方法實現代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
int a[MAXN],b[MAXN],c[MAXN];
int n,sum;

int main()
{
  scanf("%d",&n);
  for(int i=0;i<n;i++)scanf("%d",&a[i]);
  for(int i=0;i<n;i++)scanf("%d",&b[i]);
  for(int i=0;i<n;i++)scanf("%d",&c[i]);
  sort(a,a+n);
  sort(b,b+n);
  sort(c,c+n);
  sum = 0;
  for(int i=0;i<n;i++){
    int x = (lower_bound(a,a+n,b[i]) - a);
    int y = (n - (upper_bound(c,c+n,b[i]) - c));
    sum += x*y;
  }
  printf("%d\n",sum);
  return 0;
}


第七題:螺旋折線



這道題就把四個象限分一下,然后找規律遞推公式就OK了。


第八題:日志統計


這道題就是模擬一下,按id和時間排序,把相同的id,以時間遞增的情況排序,然后暴力枚舉每個id的贊數,當在規定的時間范圍內贊數大於k,標記一下,然后遞增輸出id就好了。我也不知道我寫的對不對,所以就不上代碼了。。。


第九題:全球變暖


       這道題應該會有不少人和我一樣理解成了最后還剩多少個島吧。暴力杯變成了閱讀理解杯....對於這道題,我們可以用bfs搜索一下把起初的每個島嶼都編上號,順便把可能會被淹沒的島嶼標記下來,然后我是倒着再遍歷一遍地圖,只要有沒有完全淹沒的島嶼,就讓島嶼數--,最后就剩下完全淹沒的島嶼數了。還有一種情況就是有人提到的一個島嶼淹沒完以后變成了兩個島嶼,那么就在這特判一下就好了。

實現代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
struct Node{
  int x,y;
  int num;
}Now,Next,S;
char MAP[1005][1005];
int vis[1005][1005];
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
int n,sum;

bool in(int x,int y){
  if(x >= 0 && y >= 0 && x < n && y < n)return true;
  return false;
}

bool Check(int x,int y){
  for(int i=0;i<4;i++){
    int X = x + dir[i][0];
    int Y = y + dir[i][1];
    if(MAP[X][Y] == '.' && in(X,Y))return true;
  }
  return false;
}

void bfs(){
  queue<Node> q;
  S.num = sum;
  q.push(S);
  while(!q.empty()){
    Now = q.front();
    q.pop();
    if(Check(Now.x,Now.y)){
      vis[Now.x][Now.y] = 1;
    }
    for(int i=0;i<4;i++){
      Next.x = Now.x + dir[i][0];
      Next.y = Now.y + dir[i][1];
      if(in(Next.x,Next.y) && MAP[Next.x][Next.y] == '#' && vis[Next.x][Next.y] != 1){
        if(vis[Next.x][Next.y] == 0)vis[Next.x][Next.y] = 2;
        Next.num = Now.num;
        q.push(Next);
      }
    }
  }
  sum++;
  return ;
}

int main()
{
  scanf("%d",&n);
  for(int i=0;i<n;i++){
    scanf("%s",MAP[i]);
  }
  memset(vis,0,sizeof(vis));
  sum = 0;
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      if(MAP[i][j] == '#'){
        if(vis[i][j] != 0)continue;
        S.x = i;
        S.y = j;
        bfs();
      }
    }
  }
  for(int i=n-1;i>=0;i--){
    for(int j=n-1;j>=0;j--){
      if(MAP[i][j] == '#' && vis[i][j] == 2){
        sum--;
      }
    }
  }
  printf("%d\n",sum>0?sum:0);
  return 0;
}


第十題:乘積最大



最后一道題我也不會寫,當時是隨便暴力了一下過了樣例就交了,看了一下別人的題解,確實再給我4個小時我也寫不出來...

仔細思考你會發現其實最終答案為負數只有兩種情況
①k=n,這n個數都是負數並且n是奇數
②k是奇數,並且這n個數都是負數
其它情況下答案一定為正或者0
為什么呢?一個很簡單的證明就是如果你結果為負數,那么你一定可以通過少乘一個負數多乘一個正數,或者少乘一個正數多乘一個負數把答案變成正的

然后正數的情況就好辦了
一個很完美的方法就是所有負數取絕對值從大到小排序,所有正數從大到小排序
然后暴力負數選多少個,中間取個最大的就行了
但是這樣你肯定不能取模,因為取模就錯了,然而直接乘會爆long long
熟練的話你可以寫個大整數乘法,不過肯定會超時所以要FFT優化乘法
不會FFT怎么辦?
還是將所有負數取絕對值從大到小排序,所有正數從大到小排序
然后一個一個取,每次都取當前最大的數
如果最后剛好為整數,那完美直接輸出

如果最后為負數就說明你要調整一下,也就是少乘一個負數多乘一個正數,或者少乘一個正數多乘一個負數,這個時候你只要比一下哪個更大就應該ok!


        明年再戰...


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com