CSU - 1917 There is no SSR (概率dp+矩阵优化)

In the ACMers of CSU, Zihao LI is a fan of yinyangshi. However, he has African blood in his veins. One day, he collected many charms to conjure Shikigami, which Chinese called shishen. Shishen has three levels:SSR, SR, R, and SSR is a rarity, R is ordinary, SR is between them. For most people, they can get one SSR, nineteen SR, and eighty R when he uses 100 charms. But Mr.Li is different. He can’t get SSR for his African blood...So, the score of luck for poor Mr.Li depend to the number of SR he gets in succession. Now, we know the probability of Mr.Li to conjure R, SR and the sum is equal to one. We want to know the probability of Mr.Li getting n SR in succession, which means he is lucky.

Input

There are many tests. Each case has two floats represent the probability of R, SR(0 < p1, p2 < 1)and two integer n (0 < n <= 100)as described above and m (0 < m <=1e7), the numbers of charms.

Output

For each test case, print a single float on its own line denoting the probability of Mr.Li getting n SR in succession. The answer should be around to the 1e-6.

Sample Input

0.0 1.0 1 2
1.0 0.0 1 2
0.5 0.5 1 2

Sample Output

1.000000
0.000000
0.750000

题意:阴阳师抽奖,得到R的概率为p,得到SR的概率为1-p,求抽m次奖连续获得n个SR的概率。

思路:我们可以反过来考虑,求出不会连续得到n个SR的概率,这个问题我们可以通过简单dp递推得到【dp[i]为抽i次奖不会连续得到n个SR的概率】:

但是由于m太大,因此我们没法线性递归,而由该递推式的特点,我们发现可以通过矩阵优化,并通过矩阵快速幂的方式在n^3logm的复杂度内解决。

#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define ll long long
#define maxn 500050
struct mat{
	int n,m;
	double a[15][15];
	mat(int n,int m):n(n),m(m){}
	mat(){}
	void init(){
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				a[i][j]=0;
	}
}a;
double po[15],p,q;
int n,m;
mat mul(mat a,mat b){
	mat c(a.n,b.m);
	c.init();
	for(int i=0;i<c.n;i++)
		for(int j=0;j<c.m;j++)
			for(int k=0;k<a.m;k++)
				c.a[i][j]+=a.a[i][k]*b.a[k][j];
	return c;
}
double matPow(int n){ 
	mat b(a.n,1); b.init();
	for(int i=0;i<a.n;i++)
		b.a[i][0]=1;
	while(n){
		if(n&1)
			b=mul(a,b);
		a=mul(a,a);
		n/=2;
	}
	return b.a[0][0];
}
int main(void){
	while(scanf("%lf%lf%d%d",&p,&q,&n,&m)!=EOF){
		if(q==0){
			printf("0.000000\n");
			continue;
		}
		po[0]=1;
		a=mat(n,n);
		a.init();
		for(int i=1;i<=n;i++)
			po[i]=po[i-1]*q;
		for(int i=n-1;i>=0;i--)
			a.a[0][i]=po[i]*p;
		for(int i=1;i<n;i++)
			a.a[i][i-1]=1.0;
		printf("%f\n",1.0-matPow(m-n+1));
	}
	return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值