题意:
思路:
1.当时首先在分数取模那里卡了一下,以为要求逆元,但是其实给的概率就是在取模意义下,要的结果也是在取模意义下的概率,所以其实直接用取模意义下的概率进行概率的求解即可。
2.这道题在不考虑时间复杂度的情况下要求出x道题正确的概率很简单,普通的概率乘法公式即可。但是每次都去枚举哪些题正确哪些题错误的话时间复杂度达到了O(n^3)。故要考虑怎么“记忆”当前状态前面已经枚举过的状态,故采用递推的方式。
设f(i,j)表示前 i 道题做对 j 道的概率(此处概率均指取模意义下)。
设p[i]为第 i 题正确的概率,q[i]为第 i 道题错误的概率。
则有状态转移方程:f(i,j)=f(i-1,j) q[i] + f(i-1,j-1) p[i],注意j==0时没有右式的第二项。起点f(0,0)为取模意义下的1。
这样时间复杂度变为O(n^2)
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=2020;
ll p[maxn];//p[i]表示第i道题做对的概率;
ll q[maxn];//q[i]表示第i道题做错的概率;
ll f[maxn][maxn];//f[i][j]表示前i道题做对j道的mod意义下的概率;
//状态转移方程为f[i][j]=(f[i-1][j]*q[i]%mod+f[i-1][j-1]*p[i]%mod)%mod;
int main()
{
int i,j;
int n;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%lld",&p[i]);
q[i]=(1-p[i]+mod)%mod;
}
memset(f,false,sizeof(f));
f[0][0]=mod+1;
for(i=1;i<=n;i++)
{
for(j=0;j<=i;j++)
{
if(j!=0) f[i][j]=(f[i-1][j]*q[i]%mod+f[i-1][j-1]*p[i]%mod)%mod;
else f[i][j]=f[i-1][j]*q[i]%mod;
}
}
for(i=0;i<=n;i++)
{
if(i!=n)
{
printf("%lld ",f[n][i]);
}
else
{
printf("%lld\n",f[n][i]);
}
}
return 0;
}