洛谷P1297 [国家集训队]单选错位 题解
题目链接:P1297 [国家集训队]单选错位
题意:
gx 和 lc 去参加 noip 初赛,其中有一种题型叫单项选择题,顾名思义,只有一个选项是正确答案。
试卷上共有 $n$ 道单选题,第 $i$ 道单选题有 $a_i$ 个选项,这 $a_i$ 个选项编号是 $1,2,3,\ldots,a_i$,每个选项成为正确答案的概率都是相等的。
lc 采取的策略是每道题目随机写上 $1 \sim a_i$ 的某个数作为答案选项,他用不了多少时间就能期望做对 $\sum_{i=1}^n \frac{1}{a_i}$ 道题目。gx 则是认认真真地做完了这 $n$ 道题目,可是等他做完的时候时间也所剩无几了,于是他匆忙地把答案抄到答题纸上,没想到抄错位了:第 $i$ 道题目的答案抄到了答题纸上的第 $i+1$ 道题目的位置上,特别地,第 $n$ 道题目的答案抄到了第 $1$ 道题目的位置上。
现在 gx 已经走出考场没法改了,不过他还是想知道自己期望能做对几道题目,这样他就知道会不会被 lc 鄙视了。
我们假设 gx 没有做错任何题目,只是答案抄错位置了。
输入格式:
$n$ 很大,为了避免读入耗时太多,输入文件只有 $5$ 个整数参数 $n, A, B, C, a_1$,由上交的程序产生数列 $a$。下面给出 C/C++ 的读入语句和产生序列的语句(默认从标准输入读入):
// for C/C++ scanf("%d%d%d%d%d", &n, &A, &B, &C, a + 1); for (int i = 2; i <= n; i++) a[i] = ((long long) a[i - 1] * A + B) % 100000001; for (int i = 1; i <= n; i++) a[i] = a[i] % C + 1;
选手可以通过以上的程序语句得到 $n$ 和数列 $a$($a$ 的元素类型是 $32$ 位整数),$n$ 和 $a$ 的含义见题目描述。
输出格式:
输出一个实数,表示 gx 期望做对的题目个数,保留三位小数。
对于 $100\%$ 的数据,$2\leq n\leq 10^7, 0\leq A,B,C \leq 10^8$,$1 \leq a_i \leq 10^8$。
简单的概率题。稍微分讨一下就好了。
- 当 $a_i = a_{i+1}$ 时,期望为 $\frac{1}{a_i} = \frac{1}{a_{i+1}}$
- 当 $a_i > a_{i+1}$ 时,期望为 $\frac{a_{i+1}}{a_i}\times\frac{1}{a_{i+1}} = \frac{1}{a_i}$
- 当 $a_i < a_{i+1}$ 是,期望为 $\frac{a_i}{a_{i+1}} \times \frac{1}{a_i}=\frac{1}{a_{i+1}}$
所以答案其实就是 $\sum \frac{1}{\max\{a_{i},a_{i+1}\}}$
时间复杂度 $\mathcal{O}(n)$
代码:
#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
typedef long long ll;
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e7+15))
double res; int n,A,B,C,a[N];
void gen()
{
cin >> n >> A >> B >> C >> a[1];
for(int i=2; i<=n; i++)
a[i] = ((ll)a[i - 1] * A + B) % 100000001;
for(int i=1; i<=n; i++) a[i] = a[i] % C + 1;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
cout << fixed << setprecision(3);
gen(); res = 1.0 / (max(a[1], a[n]));
for(int i=2; i<=n; i++)
res += 1.0 / (max(a[i], a[i-1]));
cout << res << '\n';
return 0;
}