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

试题A:购物单(结果填空)

题意
在这里插入图片描述

以下是让人头疼的购物单,为了保护隐私,物品名称被隐藏了。
**** 180.90 88折
**** 10.25 65折
**** 56.14 9折
**** 104.65 9折
**** 100.30 88折
**** 297.15 半价
**** 26.75 65折
**** 130.62 半价
**** 240.28 58折
**** 270.62 8折
**** 115.87 88折
**** 247.34 95折
**** 73.21 9折
**** 101.00 半价
**** 79.54 半价
**** 278.44 7折
**** 199.26 半价
**** 12.97 9折
**** 166.30 78折
**** 125.50 58折
**** 84.98 9折
**** 113.35 68折
**** 166.57 半价
**** 42.56 9折
**** 81.90 95折
**** 131.78 8折
**** 255.89 78折
**** 109.17 9折
**** 146.69 68折
**** 139.33 65折
**** 141.16 78折
**** 154.74 8折
**** 59.42 8折
**** 85.44 68折
**** 293.70 88折
**** 261.79 65折
**** 11.30 88折
**** 268.27 58折
**** 128.29 88折
**** 251.03 8折
**** 208.39 75折
**** 128.88 75折
**** 62.06 9折
**** 225.87 75折
**** 12.89 75折
**** 34.28 75折
**** 62.16 58折
**** 129.12 半价
**** 218.37 半价
**** 289.69 8折

在这里插入图片描述
做法:用文本打开以后根据关键字替换就能得到这个啦

180.90 88
10.25 65
56.14 90
104.65 90
100.30 88
297.15 50
26.75 65
130.62 50
240.28 58
270.62 80
115.87 88
247.34 95
73.21 90
101.00 50
79.54 50
278.44 70
199.26 50
12.97 90
166.30 78
125.50 58
84.98 90
113.35 68
166.57 50
42.56 90
81.90 95
131.78 80
255.89 78
109.17 90
146.69 68
139.33 65
141.16 78
154.74 80
59.42 80
85.44 68
293.70 88
261.79 65
11.30 88
268.27 58
128.29 88
251.03 80
208.39 75
128.88 75
62.06 90
225.87 75
12.89 75
34.28 75
62.16 58
129.12 50
218.37 50
289.69 80

再写以下代码计算出答案。

#include<bits/stdc++.h>
using namespace std;
int main() {
    
    
  double x, y, res = 0;
  for(int i = 1; i <= 50; ++i) {
    
    
    cin >> x >> y;
    res += x * (y / 100);
  }
  cout << res;
  return 0;
}

答案:5200(5136.86)


试题B:等差素数列(结果填空)

题意
在这里插入图片描述
做法其实搜索的时候并没有满怀信心 ,就是暴力就好了,还比较害怕数组没开够,没能找到公差更小的,其实在5000以内就够了,这谁想的到

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int prime[N], vis[N], k;
int check(int d) {
    
    
  int res = 210;
  for(int i = 0; i < k-10; ++i) {
    
    
    int f = 1, lst = prime[i];
    if(d == res) cout << lst << " ";
    for(int j = 0; j < 9; ++j) {
    
    
      if(d==res)cout << lst + d << " ";
      if(lst+d>=N) {
    
    
        f = 0; break;
      }
      if(vis[lst+d]) {
    
    
        f = 0; break;
      }
      lst = lst + d;
    }
    if(d==res) cout << endl;
    if(f) return 1;
  }
  return 0;
}
int main() {
    
    
  vis[0] = vis[1] = 1; 
  for(int i = 2; i < N; ++i) {
    
    
    if(!vis[i]) {
    
    
      prime[k++] = i; 
      for(int j = 2*i; j < N; j += i) vis[j] = 1;
    }
  }
  //for(int i = 0; i < k; ++i) printf("%d\n", prime[i]);
  for(int i = 2; i <= 1000; ++i) {
    
    
    if(check(i)) {
    
    
      cout << i; break;
    }
  }
  return 0;
}

答案:210


试题 C:承压计算(结果填空)

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

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 100;
double tu[N][N];
int main() {
    
    
  double sum = 0;
  for(int i = 1, x; i < 30; ++i) {
    
    
    for(int j = 1; j <= i; ++j) {
    
    
      cin >> x; 
      tu[i][j] += x; sum += x;
      tu[i+1][j] += tu[i][j]/2; tu[i+1][j+1] += tu[i][j]/2;
    }
  }
  double res = 0, check = 10000000000.0, sumcheck = 0;
  for(int j = 1; j <= 30; ++j) {
    
    
    sumcheck += tu[30][j];
    res = max(res, tu[30][j]);
    check = min(check, tu[30][j]);
  }
  cout << endl;
  cout << sum << " " << sumcheck << endl; 
  cout << res << " " << check << endl;
  printf("%.3lf\n", 2086458231.0 / check * res);
  return 0;
}

答案:72665192664


试题 D:方格分割(结果填空)

题意
在这里插入图片描述
p1
p2
p3

做法:可以发现一个对称的图形肯定关于中间的点对称,那么从中间的点开始搜索所到之处关于中间点对称的点也标记为1,每次走到边界就是一个新的图啦,将结果加一。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 10;
const int ne[4][2] = {
    
    1, 0, 0, 1, -1, 0, 0, -1};
int vis[N][N];
int ans;
void dfs(int x, int y) {
    
    
  if(x <= 0 || y <= 0 || x >= 6 || y >= 6) {
    
    
    ++ans; return;
  }
  for(int i = 0, tx, ty; i < 4; ++i) {
    
    
    tx = x + ne[i][0]; ty = y + ne[i][1];
    if(!vis[tx][ty] && !vis[6-tx][6-ty]) {
    
    
      vis[tx][ty] = vis[6-tx][6-ty] = 1;
      dfs(tx, ty);
      vis[tx][ty] = vis[6-tx][6-ty] = 0;
    }
  }
}
int main() {
    
    
  vis[3][3] = 1;
  dfs(3, 3);
  cout << ans/4;
  return 0;
}

答案:509


试题 E:取数位(结果填空)

题意
在这里插入图片描述
做法:考递归。
答案:f(x/10, k)


试题 F:最大公共子串(结果填空)

题意
在这里插入图片描述
在这里插入图片描述
做法:类似动态规划,上一个状态从a[i-1][j-1]转移而来。
答案:a[i-1][j-1]+1


试题 G:日期问题(程序设计)

题意
在这里插入图片描述
做法:题意很简单,但是坑很多,首先要注意闰年的情况,还有千万要去重,因为没去重找了半天的bug

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 10;
struct xx {
    
    
  int y, m, d;
  bool operator < (const xx &c) const {
    
    
    if(y != c.y) return y < c.y;
    if(m != c.m) return m < c.m;
    return d < c.d;
  }
}res[N];
int k;
int month[14] = {
    
    0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int isr(int y) {
    
    
  if(y % 4 == 0 && y % 100 != 0 || y % 400 == 0) return 1;
  return 0;
}
void solve(int a, int m, int d) {
    
    
  if(m <= 0 || m > 12 || d <= 0 || d > 31) return;
  int q = 1900, n = 2000;
  int y = q + a;
  if(y >= 1960) {
    
    
    month[2] = isr(y) ? 29 : 28;
    if(d <= month[m]) {
    
    
      res[k].y = y; res[k].m = m; res[k++].d = d;
    }
  }
  y = n + a;
  if(y <= 2059) {
    
    
    month[2] = isr(y) ? 29 : 28;
    if(d <= month[m]) {
    
    
      res[k].y = y; res[k].m = m; res[k++].d = d;
    }
  }
  return ;
}
int main() {
    
    
  int a, b, c;
  scanf("%d/%d/%d", &a, &b, &c);
  solve(a, b, c); solve(c, a, b); solve(c, b, a);
  sort(res, res+k);
  printf("%d-%02d-%02d\n", res[0].y, res[0].m, res[0].d);
  for(int i = 1; i < k; ++i) {
    
    
    if(res[i].y == res[i-1].y && res[i].m == res[i-1].m && res[i].d == res[i-1].d)
      continue;//去重!!!
    printf("%d-%02d-%02d\n", res[i].y, res[i].m, res[i].d);
  }
  return 0;
}

试题 H:包子凑数(程序设计)

题意
在这里插入图片描述
在这里插入图片描述
做法:首先要知道无法凑到无限个数字的情况是这n个数字的最大公约数不是1,然后还需要知道的是,若最大公约数是1,那么一个数字大到一定程度(10000左右),一定能由这几个数字组成,知道这两个结论后,就可以递推暴力出ac了。
代码

#include<bits/stdc++.h>
using namespace std;
const int N = 110;
const int M = 100010;
int a[N], dp[M];
int main() {
    
    
  int n; scanf("%d", &n);
  for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
  if(n == 1) {
    
    
    if(a[1] == 1) puts("0");
    else puts("INF");
    return 0;
  }
  int f = __gcd(a[1], a[2]);
  for(int i = 3; i <= n; ++i) {
    
    
    f = __gcd(f, a[i]);
  } 
  if(f != 1) {
    
    
    puts("INF"); return 0;
  }
  dp[0] = 1;
  for(int i = 1; i <= n; ++i) {
    
    
    for(int j = 0; j + a[i] < M; ++j) {
    
    
      if(dp[j]) dp[j+a[i]] = 1;
    }
  }
  int res = 0;
  for(int i = 1; i < M; ++i) {
    
    
    if(!dp[i]) ++res;
  }
  cout << res << endl;
  return 0;
} 

试题 I:分巧克力(程序设计)

题意
在这里插入图片描述
做法:二分答案,二分的时候要注意细节,二分分很多种,有靠近左边界的二分,靠近右边界的二分,这题是靠近右边界的二分,所以最后答案-1了,具体二分细节学习戳这,每次判断这个答案是否正确,用的是这个思想。

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define _for(n,m,i) for (register int i = (n); i < (m); ++i)
#define _rep(n,m,i) for (register int i = (n); i <= (m); ++i)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define PI acos(-1)
#define eps 1e-8
#define rint register int
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<double, int> pdi;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<int, int> mii;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
    
    
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') {
    
     if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') {
    
     res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int ne[8][2] = {
    
    1, 0, -1, 0, 0, 1, 0, -1, -1, -1, -1, 1, 1, -1, 1, 1};
const int INF = 0x3f3f3f3f;
const int N = 1e5+10;
const LL Mod = 1e9+7;
const int M = 1e6+10;
int h[N], w[N];
int n, k;
int check(int x) {
    
    
  LL sum = 0;
  //cout << x << ": ";
  for(int i = 0, m; i < n; ++i) {
    
    
    m = (h[i]/x)*(w[i]/x);
    sum += m;
  } 
  //cout << sum << endl;
  return sum >= k;
}
int main() {
    
    
  scanf("%d %d", &n, &k);
  for(int i = 0; i < n; ++i) scanf("%d %d", &h[i], &w[i]);
  int l = 1, r = N, mid;
  while(l < r) {
    
    
    mid = l + r >> 1;
    if(check(mid)) l = mid + 1;
    else r = mid;
  }
  printf("%d\n", l-1);
  return 0;
}


试题 J:k倍区间(程序设计)

题意
在这里插入图片描述

做法:是一个前缀和思维问题,我真的觉得最后一题比前面的题目要简单 。可以有一个简单的猜想,这个区间问题可以轻易的转化成,前缀和中两个数的差值是k的倍数,那么也就是说要满足(sum[j]-sum[i])%k==0,也就是说sum[j]%k == sum[i]%k,也就是说,如果前缀和中两个数字取膜k等于相同的数字,那么这两个数字相减就必是k的倍数,这两个数字构成的区间就是k倍区间。

首先看样例
数组为 0 1 2 3 4 5
前缀和为 0 1 3 6 10 15
前缀和膜k为 0 1 1 0 0 1
能构成的区间就有 C 3 2 + C 3 2 = 6 C_3^2 + C_3^2 = 6 C32+C32=6个,分别是(0,3],(0,4],(1,2],(1,5],(2,5],(3,4]

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define _for(n,m,i) for (register int i = (n); i < (m); ++i)
#define _rep(n,m,i) for (register int i = (n); i <= (m); ++i)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define PI acos(-1)
#define eps 1e-8
#define rint register int
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<double, int> pdi;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<int, int> mii;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
    
    
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') {
    
     if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') {
    
     res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int ne[8][2] = {
    
    1, 0, -1, 0, 0, 1, 0, -1, -1, -1, -1, 1, 1, -1, 1, 1};
const int INF = 0x3f3f3f3f;
const int N = 1e5+10;
const LL Mod = 1e9+7;
const int M = 1e6+10;
LL sum[N], a[N], cnt[N];
int main() {
    
    
  int n, k;
  scanf("%d %d", &n, &k);
  _rep(1, n, i) {
    
    
    scanf("%lld", &a[i]); 
    sum[i] = (sum[i-1] + a[i]) % k;
    ++cnt[sum[i]];
  }
  ++cnt[0];
  LL res = 0;
  //cout << cnt[0] << " " << cnt[1] << endl;
  _for(0, k, i) {
    
    
    if(cnt[i] > 1) res += cnt[i] * (cnt[i]-1) / 2;
  }
  printf("%lld\n", res);
  return 0;
}




猜你喜欢

转载自blog.csdn.net/qq_43408978/article/details/108128841