「国家集训队」单选错位 题解
作者:互联网
「国家集训队」单选错位 题解
题目大意
试卷上共有 $ n $ 道单选题,第 $ i $ 道题有 $ a_i $ 个选项,每个选项成为正确答案的概率都是相等的。
$ A $ 全部做对,但抄错位了:每题都向后抄了一个位置,特别地,第 $ n $ 道题目抄到了第 $ 1 $ 道题目的位置。
$ A $ 想知道自己期望能做对几道题目。
输入
输入只有 5 个整数参数 $ n, A, B, C, a_1 $ ,由上交的程序产生数列 $ a $ 。
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 $ 期望做对的题目数,保留三位小数。
样例及解释
输入
3 2 0 4 1
输出
1.167
解释
$ a={2,3,1} $ ,表示第 $ 1 $ 题有 $ 2 $ 个选项,第 $ 2 $ 题有 $ 3 $ 个选项,第 $ 3 $ 题有 $ 1 $ 个选项。
正确答案 | A的答案 | 做对题目 | 出现概率 |
---|---|---|---|
$ {1,1,1} $ | $ {1,1,1} $ | $ 3 $ | $ \frac{1}{6} $ |
$ {1,2,1} $ | $ {1,1,2} $ | $ 1 $ | $ \frac{1}{6} $ |
$ {1,3,1} $ | $ {1,1,3} $ | $ 1 $ | $ \frac{1}{6} $ |
$ {2,1,1} $ | $ {1,2,1} $ | $ 1 $ | $ \frac{1}{6} $ |
$ {2,2,1} $ | $ {1,2,2} $ | $ 1 $ | $ \frac{1}{6} $ |
$ {2,3,1} $ | $ {1,2,3} $ | $ 0 $ | $ \frac{1}{6} $ |
共有 $ 6 $ 种情况,每种情况出现的概率是 $ \frac{1}{6} $ ,A 期望做对 $ \frac{3+1+1+1+1+0}{6} = \frac{7}{6} $ 题,保留三位小数即 $ 1.167 $ 。
思路
算法选择
数据范围 $ n \le 10^7 $ ,说明需要 $ O(n) $ 的算法解决。推测是递推
,贪心
或公式
。
深入思考
通过样例仔细观察后,我们可以发现,第 $ i $ 题是否正确,只与第 $ i-1 $ 题的答案是否跟第 $ i $ 题相同有关。所以可以选择公式
法。
举个例子:
$ a={2,3,1} $
对于第 $ 1 $ 题和第 $ 2 $ 题,正确答案的总情况数为 $ a[1] \times a[2] = 6 $ ,而两道题答案相同的只有 $ min(a[1],a[2]) = 2 $ 种。最终做对的概率为 $ \frac{min(a[1],a[2])}{a[1] \times a[2]} = \frac{1}{3} $ 。
为什么要求最小值?
因为当第二题答案为 3 时,第一题答案不可能与它相同。所以相同情况数取决于它们的最小值。
由上可得:两道题的正确答案情况总数为 $ a[i] \times a[i-1] $ ,两道题答案相等的情况有 $ min(a[i],a[i-1]) $ 种,所以答案需要加上一个 $ \frac{min(a[i],a[i-1])}{a[i] \times a[i-1]} $ 。
化简一下:
$ \ \ \ \ \ \frac{min(a[i],a[i-1])}{a[i] \times a[i-1]} $
$ = \frac{1}{max(a[i],a[i-1])} $
注意,这里的 $ min $ 变成了 $ max $ 。
-
当 $ min(a[i],a[i-1]) = a[i] $ 时,原式变为 $ \frac{1}{a[i-1]} $ ;
-
当 $ min(a[i],a[i-1]) = a[i-1] $ 时,原式变为 $ \frac{1}{a[i]} $ 。
综合一下,就是 $ \frac{1}{max(a[i],a[i-1])} $ 。
对于特殊情况只需要再加上 $ \frac{1}{max(a[n],a[1])} $ 即可。
最终公式为:
$ ans = \frac{1}{max(a[n],a[1])} + \underset{i = 2}{\overset{n}{\sum}} \frac{1}{max(a[i],a[i-1])} $
因此,代码出。
代码实现
注释版本
#include<bits/stdc++.h>
#define ll int
const ll N=10000010;//1e7+10
using namespace std;
ll n,A,B,C,a[N];
double ans;//答案
int main(){
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;
for(ll i=2;i<=n;i++){//是2~n
ans+=1.0/max(a[i],a[i-1]);//公式
}
ans+=1.0/max(a[n],a[1]);//特殊处理
printf("%.3lf",ans);//输出
return 0;
}
压行版本
???
#include<bits/stdc++.h>
const int N=100000001;
using namespace std;
int n,A,B,C,a[N],i=1;
double ans;
main(){
scanf("%d%d%d%d%d",&n,&A,&B,&C,a+1);
for(;++i<=n;)a[i]=((long long)a[i-1]*A+B)%N;
for(i=0;++i<=n;)(a[i]%=C)+=1;
for(i=1;++i<=n;)ans+=1.0/max(a[i],a[i-1]);
ans+=1.0/max(a[n],a[1]);
printf("%.3lf",ans);
}
尾声
如果你发现了问题,你可以直接回复这篇题解
如果你有更好的想法,也可以直接回复!
标签:frac,min,int,题解,d%,单选,答案,max,国家集训队 来源: https://www.cnblogs.com/zsc985246/p/16366596.html