转载请注明出处,http://blog.youkuaiyun.com/Bule_Zst/article/details/78024120
题目:https://nanti.jisuanke.com/t/17115
Bob has a not even coin, every time he tosses the coin, the probability that the coin’s front face up is qp(qp≤12)
The question is, when Bob tosses the coin kk times, what’s the probability that the frequency of the coin facing up is even number.
If the answer is XY , because the answer could be extremely large, you only need to print (X∗Y−1)mod(109+7)
Input Format
First line an integer TT, indicates the number of test cases (T≤100) .
Then Each line has 33 integer p,q,k(1≤p,q,k≤107) indicates the i-th test case.
Output Format
For each test case, print an integer in a single line indicates the answer.
样例输入
2
2 1 1
3 1 2
样例输出
500000004
555555560
题意:
扔 k次硬币,给你一次硬币向上的概率为 pq ,让你求k次硬币后向上的次数为偶数的概率
刚开始不理解样例结果是怎么出来的,后来队友提醒我-1代表的不是取倒数而是求逆元
方法一:
运用高中知识,设向上概率是a,向下为b,则答案为:
C0k∗a0∗bk+C2k∗a2∗bk−2+C4k∗a4∗bk−4.........+Ckk∗ak∗b0
暴力去求会各种超,超内存(因为要取模)、超时间
因为
(a+b)k
展开为:
C0k∗a0∗bk+C1k∗a1∗bk−1.......+Ckk∗ak∗b0
(a−b)k
展开为:
C0k∗a0∗(−b)k+C1k∗a∗(−b)k−1.........+Ckk∗ak∗(−b)0
所以答案可以转化成: ((a+b)k+(a−b)k)2
代码:
// @Team : nupt2017team12
// @Author : Zst
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
#define LL long long
#define MOD 1000000007
#define CLR(a,x) memset(a,x,sizeof(a))
#define INF 0x3f3f3f3f
#define pb push_back
#define FOR(i,a,b) for( int i = ( a ); i <= ( b ); ++i )
LL poww( LL x, int n ) {
LL base = x;
LL tmp = 1;
while( n ) {
if( ( n & 1 ) ) {
tmp = ( tmp * base ) % MOD;
}
base = ( base * base ) % MOD;
n = n >> 1;
}
return tmp;
}
int p, q, k;
int main()
{
// freopen( "B.txt", "r", stdin );
int w;
scanf( "%d", &w );
while( w-- ) {
scanf( "%d%d%d", &p, &q, &k );
LL ans = ( poww( p, k ) + poww( p-2*q, k ) ) % MOD;
LL a = poww( p, k ) * 2;
ans *= ( poww( a, MOD-2 ) ) % MOD;
printf( "%d\n",int( ans%MOD ) );
}
return 0;
}
方法二:
使用矩阵快速幂
初始化二维矩阵a
p−qp
pq
pq
p−qp
其中a[0][0]表示抛一次反面向上的概率(即正面向上0次),a[0][1]表示抛一次正面向上的概率(即正面向上1次),a[1][0]、a[1][1]同理
那么抛两次,正面向上偶数次的概率是多少呢?
两种情况
- 第一种:第一次反面朝上(0次),第二次也是反面朝上(0次),0+0为偶数
- 第二种:第一次正面朝上(1次),第二次正面朝上(1次),1+1为偶数
而 a∗a 得到的矩阵 a1 的[0][0]元素就是我们要的概率
a1[0][0]=a[0][0]∗a[0][0]+a[0][1]∗a[1][0]
此时 a1[0][0] 表示偶数次向上的概率, a1[0][1] 表示奇数次向上的概率
求抛三次
用 a1 乘 a 得到的新矩阵b的[0][0]元素就是答案
偶数次向上 乘上 0次正面向上,得到的结果还是偶数次向上
奇数次向上 乘上 1次正面向上,得到的结果变成偶数次向上的概率
注意,按照题目中的要求,分母要变成乘上逆元
代码:
// @Team : nupt2017team12
// @Author : Zst
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
#define LL long long
#define MOD 1000000007
#define CLR(a,x) memset(a,x,sizeof(a))
#define INF 0x3f3f3f3f
#define pb push_back
#define FOR(i,a,b) for( int i = ( a ); i <= ( b ); ++i )
struct Matrix {
LL matrix[2][2];
Matrix() {
CLR( matrix, 0 );
FOR( i, 0, 1 ) {
matrix[i][i] = 1;
}
}
Matrix( const LL matrix[2][2] ) {
FOR( i, 0, 1 ) {
FOR( j, 0, 1 ) {
this->matrix[i][j] = matrix[i][j];
}
}
}
Matrix operator*( const Matrix& a ) {
Matrix res;
FOR( i, 0, 1 ) {
FOR( j, 0, 1 ) {
res.matrix[i][j] = 0;
FOR( k, 0, 1 ) {
res.matrix[i][j] = ( res.matrix[i][j] + a.matrix[i][k] * this->matrix[k][j] ) % MOD;
}
}
}
return res;
}
};
int p, q, k;
Matrix poww( const Matrix& a, int n ) {
Matrix base( a.matrix );
Matrix res;
while( n ) {
if( ( n & 1 ) ) {
res = res * base;
}
n = n >> 1;
base = base * base;
}
return res;
}
LL poww( LL a, int n ) {
LL base = a;
LL res = 1;
while( n ) {
if( ( n & 1 ) ) {
res = ( res * base ) % MOD;
}
base = ( base * base ) % MOD;
n = n >> 1;
}
return res;
}
int main()
{
// freopen( "B.txt", "r", stdin );
int w;
scanf( "%d", &w );
while( w-- ) {
scanf( "%d%d%d", &p, &q, &k );
LL a = ( ( p - q ) * poww( p, MOD-2 ) ) % MOD;
LL b = ( q * poww( p, MOD-2 ) ) % MOD;
LL tmp[2][2] = {
{ a, b },
{ b, a }
};
Matrix res( tmp );
res = poww( res, k );
printf( "%d\n",int( res.matrix[0][0] ) );
}
return 0;
}