A 你几岁了 - 输入与输出

给定一个整数 $x$,输出 $\texttt{I am } x \texttt{ years old.}$。
  • 直接输出即可。记得空格
int x;
cin >> x;
cout << "I am " << x << " years old.";
  • 也可以使用更直观的 printf 进行输出。
int x;
scanf("%d", &x);  // cin >> x;
printf("I am %d years old.", x);

B 求和 - 循环结构

给定一个整数 $n$,输出 $n$ 行,第 $i$ 行输出 $1$ 到 $i$ 的和。
  • 开一个变量 $sum$ 记录 $1$ 到 $i$ 的和,从 $1$ 循环到 $n$,每次循环更新一次 $sum$,然后输出。
  • 注意到,提示给出了 $1 + 2 + 3 + \cdots + 1000000 > 2147483647$,并且 $n \le 10^7$,这告诉我们,答案可能超出 int 的范围,需要使用 long long
  • 由于使用 endl 的输出效率太低,题目中写清了更优的换行方式,即输出 \n求求大家好好读读题吧。
int n;
long long sum;

cin >> n;
for (int i = 1; i <= n; ++i) {
    sum += i;
    cout << sum << "\n";
}

C 渡荆门送别 - 循环结构与数组

给定一个整数 $n$ 和一个序列 $a$,求序列中每个元素分别与最大值和最小值的差。
  • 首先定义两个变量 $maxn$ 和 $minn$,用于存储最大值和最小值。
  • 值得注意的是,因为 $minn$ 存储的数列中的最小值,因此需要将其初始化为一个极大值,如 $10^{18}$。同理 $maxn$ 应该初始化为一个极小值,如 $0$。
  • 输入序列 $a$ 的同时更新 $maxn$ 和 $minn$,得到序列 $a$ 中最大元素与最小元素的值。
  • 遍历两次序列 $a$,第一次输出 $maxn - a[i]$,第二次输出 $a[i] - minn$ 即可。
  • 注意到,$a_i \le 10^{18}$ ,需要开 long long
const int N = 1e6 + 10;
const long long INF = 1e18;
int n;
long long a[N], minn = INF, maxn;

cin >> n;
for (int i = 1; i <= n; ++i) {
    cin >> a[i];
    maxn = max(maxn, a[i]);  // if (a[i] > maxn) maxn = a[i];
    minn = min(minn, a[i]);  // if (a[i] < minn) minn = a[i];
} for (int i = 1; i <= n; ++i)
    cout << maxn - a[i] << ' ';
cout << "\n";
for (int i = 1; i <= n; ++i)
    cout << a[i] - minn << ' ';

D 影子字符串 - 字符串

输入若干个字符串,如果之前没有出现过这个字符串就输出,否则跳过。

遇到字符串 $\texttt{0}$ 结束程序。

  • 可以使用一个数组 $a$ 记录之前出现过的字符串,每次读入一个字符串 $s$ 都遍历一次 $a$。
  • 如果发现 $a[i]$ 与 $s$ 相同则表示之前出现过这个字符串,那么跳过,继续输入下一个 $s$。
  • 否则说明没有出现过,那么输出这个字符串,并且将它存到数组中即可。
  • 如果读到 $s$ 为字符串 $\texttt{0}$,那么跳出循环,结束程序。
const int N = 510;
string s, a[N];
int cnt;  // 存储 a 中有多少个元素
bool flag;

while (cin >> s) {
    if (s == "0") break;
    flag = false;  // 判断 a 中是否有 s,有为 true,无为 false
    for (int i = 1; i <= n; ++i) if (a[i] == s) {
        flag = true;  // 如果有就将 flag 改为 true
        break;
    } if (!flag) cout << (a[++cnt] = s);  // {++cnt; a[cnt] = s; cout << s;}
}

E 天天爱跑步 - 综合应用

一共有 $n$ 天,每签到一天可以得到相应的活跃值奖励,连续签到可以获得连续签到奖励。

当连续签到天数达到以下天数时,活跃值奖励将发生如下变化。

  • $1$ 天:由 $0$ 变为 $v_1$
  • $3$ 天:由 $v_1$ 变为 $v_3$
  • $7$ 天:由 $v_3$ 变为 $v_7$
  • $30$ 天:由 $v_7$ 变为 $v_{30}$
  • $120$ 天:由 $v_{30}$ 变为 $v_{120}$
  • $365$ 天:由 $v_{120}$ 变为 $v{365}$
  • $366$ 天或更多天数:均为 $v_{365}$

给出连续签到奖励以及 $n$ 天的签到情况,求出 天后获得的活跃值为多少。

  • 按题意模拟即可。
  • 读入 $n$,读入六个连签奖励,接下来读入 $n$ 天的签到情况。
  • 开一个变量 $cnt$ 用于记录连续签到的天数。如果当天签到了,则给 $cnt$ 加 $1$,并且给答案加上对应的活跃值奖励,否则给 $cnt$ 归零。
int n, v1, v3, v7, v30, v120, v365, x, cnt, ans;  // cnt 用于记录连签天数

cin >> n >> v1 >> v3 >> v7 >> v30 >> v120 >> v365;
for (int i = 1; i <= n; ++i) {
    cin >> x;
    if (x) {
        ++cnt;
        if (cnt >= 1 && cnt < 3) ans += v1;
        else if (cnt >= 3 && cnt < 7) ans += v3;
        else if (cnt >= 7 && cnt < 30) ans += v7;
        else if (cnt >= 30 && cnt < 120) ans += v30;
        else if (cnt >= 120 && cnt < 365) ans += v120;
        else if (cnt >= 365) ans += v365;
    } else cnt = 0;
} cout << ans << "\n";

F Function - 函数递归

给定递归函数:

$$ w(a, b, c) = \begin{equation} \begin{cases} 1 & a \le 0 \text{ or } b \le 0 \text{ or } c \le 0 \\ w(20, 20, 20) & a > 20 \text{ or } b > 20 \text{ or } c > 20 \\ w(a, b, c - 1) + w(a, b - 1, c - 1) - w(a, b - 1, c) & a < b < c \text{ and } a, b, c \in [1, 20] \\ w(a - 1, b, c) + w(a - 1, b - 1, c) + w(a - 1, b, c - 1) - w(a - 1, b - 1, c - 1) & \text{otherwise} \end{cases} \end{equation} $$

给出若干组 $a$、$b$ 和 $c$ 的值,求出 $w(a, b, c)$ 的值。

  • 注意到,由于函数中进行了大量递归,效率变得十分低下。
  • 可以发现,我们在递归时,进行了大量的重复计算。考虑记忆化
  • 新建一个三维数组 $f$,对每组 $a$、$b$ 和 $c$,把这些重复的值记录下来,递归时发现已经计算过就直接返回,显著提升了效率。
  • 由于数据范围十分庞大,我们无法记录所有的 $a$、$b$ 和 $c$,但可以发现的是,对于超过 $20$ 的 $a$、$b$ 和 $c$,递归一次就会变为 $w(20, 20, 20)$,因此只需要记录 $1$ 到 $20$ 之间的 $f[a][b][c]$ 即可。
const int N = 25;
int f[N][N][N];

long long w(long long a, long long b, long long c) {
    if (a <= 0 || b <= 0 || c <= 0) return 1;
    if (a > 20 || b > 20 || c > 20) return w(20, 20, 20);
    if (f[a][b][c]) return f[a][b][c];
    if (a < b && b < c) f[a][b][c] = w(a, b, c - 1) + w(a, b - 1, c - 1) - w(a, b - 1, c);
    else f[a][b][c] = w(a - 1, b, c) + w(a - 1, b - 1, c) + w(a - 1, b, c - 1) - w(a - 1, b - 1, c - 1);
    return f[a][b][c];
}
最后修改:2024 年 02 月 03 日
如果觉得我的文章对你有用,请随意赞赏