P8714 填空问题 题解

填空问题

题意

自己看(

思路

分五个小题去考虑。

问题 A

枚举门牌号,看门牌号中有多少个 \(2\),统计答案即可。

点击查看代码
void SolveA () { // 问题 A
  int sum = 0;
  for (int i = 1, j; i <= 2020; i++) { // 枚举门牌号
    j = i;
    while (j) { // 枚举每一位
      sum += (j % 10 == 2); // 统计 2 的数量
      j /= 10;
    }
  }
  cout << sum;
}

输出答案:\(624\)

问题 B

枚举分子和分母,判断分子分母是否互质,统计互质的分子分母对数。

点击查看代码
int gcd (int x, int y) { // 欧几里得算法求最小公因数
  return (y ? gcd(y, x % y) : x);
}
void SolveB () { // 问题 B
  int sum = 0;
  for (int i = 1; i <= 2020; i++) {
    for (int j = 1; j <= 2020; j++) { // 先枚举分子分母
      sum += (gcd(i, j) == 1); // 判断是否互质
    }
  }
  cout << sum;
}

输出答案:\(2481215\)

问题 C

开始有难度了哟。

首先画一个草图:

经过观察,我们可以发现:对于每个整数 \(x\),位于 \((x,x)\) 的数所在的红线箭头都是从下往上的。

那么答案要求的那个数必然也在一条从下往上的红线上。

再观察一下,贯穿 \((x,x)\) 的红线起始点在 \((2x - 1,1)\) 上。

再推一下,假设我们现在求的是位于 \((3,3)\) 的数,可以发现:

这里有一个三角形,三角形中的数的个数再加上 \(x\) 就是答案!三角形中的数的个数也很好求,就是 \(1 + 2 + 3 + \cdots + (2x - 2)\)

综上所述,求位于 \((x,x)\) 的数的公式就是 \((1 + 2x - 2) \times (2x - 2) / 2 + x\)

点击查看代码
void SolveC () { // 问题 C
  int x = 20 * 2 - 1;
  cout << (x * (x - 1) / 2 + 20); // 套用公式
}

输出答案:\(761\)

问题 D

模拟一下,有些细节,处理号闰年和星期等问题就行了。具体看代码。

点击查看代码
const int D[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 每一个月的天数

bool leap (int y) { // 判断闰年,如果是闰年则返回值为 1,否则返回值为 0
  if (y % 100) { // 不是整百年
    return !(y % 100 % 4);
  }
  y /= 100; // 是整百年
  return !(y % 4);
}
bool check (int y, int m, int d) { // 判断是否已经求完了所有日子。
  return !(y == 2020 && m == 10 && d == 2); // 因为包含了 2020.10.1,所以要往后一天
}
void SolveD () { // 问题 D
  int y = 2000, m = 1, d = 1, z = 6, ans = 0; // y 为年份,m 为月份,d 为日期,z 为星期几,ans 为答案
  while (check(y, m, d)) { // 判断
    ans++; // 每天至少跑 1 km
    if (z == 1 || d == 1) { // 特殊日子
      ans++; // 再跑 1 km
    }
    d++, z = z % 7 + 1; // 处理日期变更
    if (m != 2 || !leap(y)) { // 不是二月或不是闰年
      if (d == D[m] + 1) { // 正常处理
        m++, d = 1;
      }
    } else { // 是闰二月
      if (d == 30) { // 特殊处理
        m++, d = 1;
      }
    }
    if (m == 13) { // 一年又过完了
      y++, m = 1; // 新的一年!
    }
  }
  cout << ans;
}

输出答案:\(8879\)

问题 E

看了一下题解区,实现也没简单到哪去,枚举一下每个二极管亮或不亮,从某一个亮着的二极管开始做一次深搜,判断是否可以只通过亮着的二极管走到所有二极管。

先建一张图我蠢了用了个邻接表,可以通过枚举二进制数来方便的枚举每种情况,统计答案即可。

点击查看代码
void pret () { // 日常犯蠢 1/1
  v[0].push_back(1), v[0].push_back(5);
  v[1].push_back(0), v[1].push_back(2), v[1].push_back(6);
  v[2].push_back(1), v[2].push_back(3), v[2].push_back(6);
  v[3].push_back(2), v[3].push_back(4);
  v[4].push_back(3), v[4].push_back(5), v[4].push_back(6);
  v[5].push_back(0), v[5].push_back(4), v[5].push_back(6);
  v[6].push_back(1), v[6].push_back(2), v[6].push_back(4), v[6].push_back(5);
}
void dfs (int x) { // 简单 dfs
  if (vis[x] || !f[x]) {
    return ;
  }
  vis[x] = 1, num++;
  for (int i : v[x]) {
    dfs(i);
  }
}
void SolveE () { // 问题 E
  int sum = 0;
  pret(); // 预处理
  for (int i = 1; i < (1 << 7); i++) { // 枚举二进制对应的十进制数
    int st = 7, cnt = 0; // st 为任意的一个亮着的二极管,我就编号取最小的一个
    num = 0;
    for (int j = 0; j < 7; j++) { // 二进制拆分
      f[j] = ((i >> j) & 1), vis[j] = 0;
      if (f[j]) {
        st = min(st, j), cnt++;
      }
    }
    dfs(st); // 做一次深搜
    sum += (num == cnt); // 如果能够找到所有发光二极管,答案加 1
  }
  cout << sum;
}

输出答案:\(80\)

好了,到这里,所有小题全部解决了,总体代码 \(126\) 行,对我来说是比较长的了。

Code

点击查看完整版代码
#include <iostream>
#include <vector>

using namespace std;

const int D[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 每一个月的天数

char c;
vector<int> v[10];
bool vis[10], f[10];
int num;

void pret () { // 日常犯蠢 1/1
  v[0].push_back(1), v[0].push_back(5);
  v[1].push_back(0), v[1].push_back(2), v[1].push_back(6);
  v[2].push_back(1), v[2].push_back(3), v[2].push_back(6);
  v[3].push_back(2), v[3].push_back(4);
  v[4].push_back(3), v[4].push_back(5), v[4].push_back(6);
  v[5].push_back(0), v[5].push_back(4), v[5].push_back(6);
  v[6].push_back(1), v[6].push_back(2), v[6].push_back(4), v[6].push_back(5);
}
int gcd (int x, int y) { // 欧几里得算法求最小公因数
  return (y ? gcd(y, x % y) : x);
}
bool leap (int y) { // 判断闰年,如果是闰年则返回值为 1,否则返回值为 0
  if (y % 100) { // 不是整百年
    return !(y % 100 % 4);
  }
  y /= 100; // 是整百年
  return !(y % 4);
}
bool check (int y, int m, int d) { // 判断是否已经求完了所有日子。
  return !(y == 2020 && m == 10 && d == 2); // 因为包含了 2020.10.1,所以要往后一天
}
void dfs (int x) { // 简单 dfs
  if (vis[x] || !f[x]) {
    return ;
  }
  vis[x] = 1, num++;
  for (int i : v[x]) {
    dfs(i);
  }
}

void SolveA () { // 问题 A
  int sum = 0;
  for (int i = 1, j; i <= 2020; i++) { // 枚举门牌号
    j = i;
    while (j) { // 枚举每一位
      sum += (j % 10 == 2); // 统计 2 的数量
      j /= 10;
    }
  }
  cout << sum;
}
void SolveB () { // 问题 B
  int sum = 0;
  for (int i = 1; i <= 2020; i++) {
    for (int j = 1; j <= 2020; j++) { // 先枚举分子分母
      sum += (gcd(i, j) == 1); // 判断是否互质
    }
  }
  cout << sum;
}
void SolveC () { // 问题 C
  int x = 20 * 2 - 1;
  cout << (x * (x - 1) / 2 + 20); // 套用公式
}
void SolveD () { // 问题 D
  int y = 2000, m = 1, d = 1, z = 6, ans = 0; // y 为年份,m 为月份,d 为日期,z 为星期几,ans 为答案
  while (check(y, m, d)) { // 判断
    ans++; // 每天至少跑 1 km
    if (z == 1 || d == 1) { // 特殊日子
      ans++; // 再跑 1 km
    }
    d++, z = z % 7 + 1; // 处理日期变更
    if (m != 2 || !leap(y)) { // 不是二月或不是闰年
      if (d == D[m] + 1) { // 正常处理
        m++, d = 1;
      }
    } else { // 是闰二月
      if (d == 30) { // 特殊处理
        m++, d = 1;
      }
    }
    if (m == 13) { // 一年又过完了
      y++, m = 1; // 新的一年!
    }
  }
  cout << ans;
}
void SolveE () { // 问题 E
  int sum = 0;
  pret(); // 预处理
  for (int i = 1; i < (1 << 7); i++) { // 枚举二进制对应的十进制数
    int st = 7, cnt = 0; // st 为任意的一个亮着的二极管,我就编号取最小的一个
    num = 0;
    for (int j = 0; j < 7; j++) { // 二进制拆分
      f[j] = ((i >> j) & 1), vis[j] = 0;
      if (f[j]) {
        st = min(st, j), cnt++;
      }
    }
    dfs(st); // 做一次深搜
    sum += (num == cnt); // 如果能够找到所有发光二极管,答案加 1
  }
  cout << sum;
}

int main () {
  // freopen("output", "w", stdout);
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> c;
  if (c == 'A') {
    SolveA();
  } else if (c == 'B') {
    SolveB();
  } else if (c == 'C') {
    SolveC();
  } else if (c == 'D') {
    SolveD();
  } else {
    SolveE();
  }
  return 0;
}
点击查看简略版代码
#include<iostream>

using namespace std;

int ans[5] = {624, 2481215, 761, 8879, 80};
char c;

int main() {
  cin >> c;
  cout << ans[c - 'A'];
  return 0;
}
posted @ 2023-05-09 11:45  wnsyou  阅读(20)  评论(0编辑  收藏  举报