from 2017 ACM-ICPC 亚洲区(西安赛区)网络赛 B. Coin
Bob has a not even coin, every time he tosses the coin, the probability that the coin's front face up is
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 , because the answer could be extremely large, you only need to print
Input Format
First line an integer TT, indicates the number of test cases .
Then Each line has 33 integer 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次硬币,给你一次硬币向上的概率为,让你求k次硬币后向上的次数为偶数的概率
刚开始不理解样例结果是怎么出来的,后来队友提醒我-1代表的不是取倒数而是求逆元
方法一:
运用高中知识,设向上概率是a,向下为b,则答案为:
暴力去求会各种超,超内存(因为要取模)、超时间
因为
展开为:
展开为:
所以答案可以转化成:
代码:
// @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:
其中a[0][0]表示抛一次反面向上的概率(即正面向上0次),a[0][1]表示抛一次正面向上的概率(即正面向上1次),a[1][0]、a[1][1]同理
那么抛两次,正面向上偶数次的概率是多少呢?
两种情况
- 第一种:第一次反面朝上(0次),第二次也是反面朝上(0次),0+0为偶数
- 第二种:第一次正面朝上(1次),第二次正面朝上(1次),1+1为偶数
而 得到的矩阵
的[0][0]元素就是我们要的概率
此时 表示偶数次向上的概率,
表示奇数次向上的概率
求抛三次
用 乘
得到的新矩阵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;
}