2018第九届蓝桥杯大赛软件类B组C/C++省赛题解

试题 A:第几天(结果填空)

题意
在这里插入图片描述
答案:125(闰年:是4的倍数且不是100的倍数,或者是400的倍数)


试题 B:明码(结果填空)

题意
在这里插入图片描述

代码

//解析明码
#include<bits/stdc++.h>
using namespace std;
int main() {
    
    
  int x, y;
  for(int i = 0; i < 10; ++i) {
    
    
    for(int j = 0; j < 16; ++j) {
    
    
      cin >> x >> y;
      bitset<8> b1(x); bitset<8> b2(y);
      cout << b1 << b2 << endl;
    } 
  }
  return 0;
}
//求9的9次方
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
    
    
  LL res = 9;
  for(int i = 0; i < 8; ++i) {
    
    
    res = res * 9;
  } 
  cout << res << endl;
  return 0;
} 

答案:387420489


试题 C:乘积尾0(结果填空)

题意在这里插入图片描述
代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
    
    
  int x, two = 0, ten = 0;
  for(int i = 0; i < 100; ++i) {
    
    
    cin >> x;
    while(x) {
    
    
      if(x % 2 == 0) x /= 2, ++two;
      else if(x % 5 == 0) x /= 5, ++ten;
      else break;
    }
  }
  cout << min(two, ten);
  return 0;
} 

答案:31


试题 D:测试次数(结果填空)

题意在这里插入图片描述
做法:没有想到这竟然是一道动态规划题,dp[i][k]代表当前最高i楼,并且有k部手机在最佳策略下最坏情况需要测试几次。转移方程如下: d p [ i ] [ k ] = m i n ( m a x ( d p [ i − j ] [ k ] , d p [ j − 1 ] [ k − 1 ] ) + 1 , d p [ i ] [ k ] ) ; dp[i][k] = min(max(dp[i-j][k], dp[j-1][k-1]) + 1, dp[i][k]); dp[i][k]=min(max(dp[ij][k],dp[j1][k1])+1,dp[i][k]);
j代表的含义是当前正在测试j层,如果手机没碎,那么最坏情况下还需要测试i-j层,如果手机碎了,那么现在还剩下k-1部手机,且需要测试j-1层。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1000;
const int Mod = 1e5;
int dp[N+10][4];
int main() {
    
    
  memset(dp, 0x3f, sizeof dp);
  for(int i = 0; i <= N; ++i) dp[i][1] = i;
  for(int k = 2; k <= 3; ++k) {
    
    
    dp[0][k] = 0;
    for(int i = 1; i <= N; ++i) {
    
    
      for(int j = 1; j <= i; ++j) {
    
    
        dp[i][k] = min(max(dp[i-j][k], dp[j-1][k-1]) + 1, dp[i][k]);
      }
    }
  }
  cout << dp[N][3];
  return 0;
}

答案: 19


试题 E:快速排序(结果填空)

题意在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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


试题 F:递增三元组(程序设计)

题意在这里插入图片描述
做法:先对3个数组排序,再对于b数组,统计c数组中比bi大的有多少个,记录在sum数组里面,再对sum数组计算一遍前缀和,最后遍历一遍a数组,加上对应的sum数组。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+10;
int a[N], b[N], c[N];
LL sum[N];
int main() {
    
    
  int n; 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);
  int p1 = 0, p2 = 0, p3 = 0;
  LL res = 0;
  for(int i = 0; i < n; ++i) {
    
    
    while(p3 < n && c[p3] <= b[i]) ++p3;
    sum[i] = n - p3;
  }
  for(int i = n-2; i >= 0; --i) sum[i] += sum[i+1];
  for(int i = 0; i < n; ++i) {
    
    
    while(p2 < n && b[p2] <= a[i]) ++p2;
    res += sum[p2];
  }
  printf("%lld\n", res);
  return 0;
} 

试题 G:螺旋折线(程序设计)

题意
在这里插入图片描述
在这里插入图片描述

做法
在这里插入图片描述
再根据细节模拟。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
    
    
  int x, y, c, qx, qy;
  scanf("%d%d", &x, &y);
  c = max(abs(x), abs(y));
  LL res;
  qx = -c; qy = qx+1; res = 4ll*c*(c-1)+1;
  
  if(x <= 0) {
    
    
    if(y <= 0) {
    
    
      
      if(x == -c && y == qy-1) res += 8*c - 1;
      else if(x == -c) res += y - qy;
      else if(y == -c) res += 8*c-1-(x-qx);
      
    } else {
    
    
      if(x == -c) res += y - qy;
      else if(y == c) res += c-qy+x-qx;
    }
  } else {
    
    
    res += c-qy;
    if(y >= 0) {
    
    
      if(x == c) res += c-qx+c-y;
      else if(y == c) res += x-qx;
    } else {
    
    
      res += 3*c;
      if(x == c) res += -y;
      else if(y == -c) res += c + (c-x);
    }
  }
  printf("%lld\n", res);
  return 0;
}

试题 H: 日志统计(程序设计)

题意
在这里插入图片描述
在这里插入图片描述
做法:根据id存储该id所在时间,然后根据每个id进行一次滑动窗口,一旦滑动窗口里的值大于等于k,就直接输出。
代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+10;
vector<int> st[N];
int main() {
    
    
  int n, d, k;
  scanf("%d%d%d", &n, &d, &k);
  for(int i = 0, ts, id; i < n; ++i) {
    
    
    scanf("%d%d", &ts, &id);
    st[id].push_back(ts);
  }
  for(int i = 0, l, len; i < N; ++i) {
    
    
    if(st[i].size() == 0) continue;
    sort(st[i].begin(), st[i].end());
    len = st[i].size(); l = 0;
    int sum = 0;
    for(int r = 0; r < len; ++r) {
    
     
      while(st[i][r]-st[i][l] >= d) ++l, --sum;
      ++sum;
      if(sum >= k) {
    
    
        printf("%d\n", i); break;
      } 
    } 
  }
  return 0;
} 

试题 I:全球变暖(程序设计)

题意
在这里插入图片描述
在这里插入图片描述

做法:找到每个连通块(岛屿),并给每个岛屿标号,再遍历一遍标过号的vis,如果四周都没有0(海),那么这个岛屿必然不会完全沉没。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int ne[4][2] = {
    
    1, 0, 0, 1, -1, 0, 0, -1};
const int N = 1010;
char tu[N][N];
int vis[N][N], n;
void dfs(int x, int y, int k) {
    
    
  vis[x][y] = k;
  for(int i = 0, tx, ty; i < 4; ++i) {
    
    
    tx = x + ne[i][0]; ty = y + ne[i][1];
    if(tx < 1 || ty < 1 || tx > n || ty > n || vis[tx][ty] || tu[tx][ty] == '.') continue;
    dfs(tx, ty, k);
  }
}
int res[N*N];
int main() {
    
    
  scanf("%d", &n);
  for(int i = 1; i <= n; ++i) scanf("%s", tu[i]+1);
  int k = 0;
  for(int i = 1; i <= n; ++i) {
    
    
    for(int  j = 1; j <= n; ++j) {
    
    
      if(!vis[i][j] && tu[i][j] == '#') dfs(i, j, ++k);
    }
  }
  /*for(int i = 1; i <= n; ++i) {
    for(int j = 1; j <= n; ++j) cout << vis[i][j] << " ";
    cout << endl;
  }*/
  for(int i = 1, ti, tj; i <= n; ++i) for(int j = 1; j <= n; ++j) {
    
    
    if(vis[i][j] && !res[vis[i][j]]) {
    
     
      int f = 1;
      for(int k = 0; k < 4; ++k) {
    
    
        ti = i + ne[k][0]; tj = j + ne[k][1];
        if(ti < 1 || tj < 1 || ti > n || tj > n) continue;
        if(!vis[ti][tj]) {
    
    
          f = 0; break;
        }
      }
      
      if(f) res[vis[i][j]] = 1;
    }
  }
  int ans = 0;
  for(int i = 1; i <= k; ++i) {
    
    
    if(!res[i]) ++ans;
  }
  printf("%d\n", ans);
  return 0;
}

试题 J: 乘积最大(程序设计)

题意
在这里插入图片描述
在这里插入图片描述
做法:问题很简单,就是选K个数相乘结果最大,有正有负有0,那么就得分情况讨论了。

  • k是奇数
    • 全正与0或者全负与0:选最大的k个数字相乘
    • 有正有负有0:先选一个最大的正数,然后再转化成k为偶数有正有负有0的情况。
  • k是偶数
    • 全正与0:选最大的k个数字相乘
    • 全负:选最小的k个数字相乘
    • 有正有负有0:对于正数和0两个一组,负数也是两个一组,每一轮比较哪一组相乘结果比较大(注意:这里容易爆精度,因为取膜问题WA了好久还找不到bug ),选最大的一组乘上,最后特判一组只剩一正一负的情况。这就是下面的solve函数啦。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF = 1e15;
const int N = 1e5+10;
const LL Mod = 1e9+9;
int fs, n, k;
LL sum = 1, mid1, mid2, a[N];
void solve(int l, int r) {
    
     //k偶,有正有负有0
  while(l < fs-1 || r > fs) {
    
    
    mid1 = mid2 = -INF;
    if(l + 1 < fs) mid1 = a[l] * a[l+1]; 
    if(r - 1 >= fs) mid2 = a[r-1] * a[r]; 
    if(mid1 > mid2) sum = mid1 % Mod * sum % Mod, l += 2;
    else sum = mid2 % Mod * sum % Mod, r -= 2;
    k -= 2;
    if(!k) return; 
  }
  sum = sum * a[l] % Mod * a[r] % Mod;
  return ; 
} 
int main() {
    
    
  scanf("%d %d", &n, &k);
  for(int i = 0; i < n; ++i) {
    
    
    scanf("%lld", &a[i]);
    if(a[i] < 0) ++fs;
  }
  sort(a, a+n);
  if(k & 1) {
    
    
    if(fs == 0 || fs == n) {
    
     //k奇全正或者全负 0
      for(int i = n-1; i >= n-k; --i) sum = sum * a[i] % Mod;
    } else {
    
     //有正有负k奇 
      sum = sum * a[n-1] % Mod; --k;
      if(k) solve(0, n-2);
    }
  } else {
    
    
    if(!fs) {
    
     //k偶全正 0
      for(int i = n-1; i >= n-k; --i) sum = sum * a[i] % Mod;   
    } else if(fs == n) {
    
     //k偶全负 
      for(int i = 0; i < k; ++i) sum = sum * a[i] % Mod;
    } else {
    
     //有正有负k偶 
      solve(0, n-1);
    } 
  }
  printf("%lld\n", sum);
  return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_43408978/article/details/108040097
今日推荐