题解:P2942 [USACO09MAR] Moon Mooing G

· · 题解

题目传送门

题目解析

个人觉得这一题不难,但是需要对题目有一定理解。\ 第一次哞叫的时候,以 c 秒作为初始时长。\ 之后的时长有两个公式 \

$a_2\times \frac{c}{d_2} + b_2$。\ 每一次选择其中较小的一项放入数组,最后输出数组的第 $n$ 项。 特别的,如果两项为一样的,在随意放入一项的同时 $ans_1,ans_2$ 都要加一。 ### 具体做法 首先可以看到,时间 $1 < N < 4 \times 10^6$ 所以,将暴力枚举的方法 pass 掉(当然,不包括打表)。\ 但正是这一个数据范围,让我看到了一线生机。\ 可以采用模拟的方法,模拟。\ 模拟从 $1$ 到 $n$ 次的哞叫时长。\ 定义两个变量 $ans_1,ans_2$ 初值为 $1$。\ 将数组的第一位数字初值赋值为 $c$ 用 while 循环从 $2$ 到 $n$ 进行遍历。\ 如果 $f_1>f_2 \to ans_1+1$ 将 $f_1$ 放入数组。\ 如果 $f_2>f_1 \to ans_2+1$ 将 $f_2$ 放入数组。\ 如果两数相等,像上文说的 $ans_1+1,ans_2+1$ 将 $f_1,f_2$ 任意一个放入数组。\ 在上述操作中,有一点要注意,我们用于存储位数的 $i$ 每一次都要加一,直到 $i = n$ 就可以输出结果。 ### AC Code ```cpp #include<bits/stdc++.h> #define int long long using namespace std; //定义题目中所给的变量 int n, c; int timing[5000010];// timing[i] 表示第i次哞叫时长 int f1, f2, ans1, ans2; int a1, a2, b1, b2, d1, d2; signed main() { ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); // 先按题目要求输入 cin >> c >> n; cin >> a1 >> b1 >> d1 >> a2 >> b2 >> d2; // 初始化 memset(timing, 0, sizeof timing); // 更改一下首位值 timing[1] = c; ans1 = ans2 = 1; int i = 1; while(i != n) { // 题目中所给公式 // timing[ans1] 和 timing[ans2] 为上一次存储的哞叫声长度 f1 = a1 * timing[ans1] / d1 + b1; f2 = a2 * timing[ans2] / d2 + b2; if(f1 < f2) timing[++i] = f1, ans1++; else if(f1 > f2) timing[++i] = f2, ans2++; else timing[++i] = f1, ans1++, ans2++; // cout << timing[i] << ' ' << ans1 << ' ' << ans2 << '\n'; } // 据题意排序 sort(timing + 1, timing + n + 1); cout << timing[n] << '\n'; return 0; } ```