2017 ACM-ICPC 亚洲区(西安赛区)网络赛 Coin 矩阵快速幂

Bob has a not even coin, every time he tosses the coin, the probability that the coin's front face up is \frac{q}{p}(\frac{q}{p} \le \frac{1}{2})pq​​(pq​​21​​).

The question is, when Bob tosses the coin kktimes, what's the probability that the frequency of the coin facing up is even number.

If the answer is \frac{X}{Y}YX​​, because the answer could be extremely large, you only need to print (X * Y^{-1}) \mod (10^9+7)(XY1​​)mod(109​​+7).

Input Format

First line an integer TT, indicates the number of test cases (T \le 100T100).

Then Each line has 33 integer p,q,k(1\le p,q,k \le 10^7)p,q,k(1p,q,k107​​) 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
题意:给定n,m,k,每次抛一个硬币为正面朝上的概率为(m/n),求抛k次硬币之后,硬币朝上的概率为多少(这里输出的是逆元之后的结果,所以很大)
题解:我们把概率转换为事件,一共n^k次事件,我们每扔一次硬币就可以看作有n次操作,m次为硬币朝上,n-m次硬币朝下。
我们设b(n)为抛n次硬币之后,硬币朝上次数为奇数的操作次数;a(n)为抛k次硬币之后,硬币朝上次数为偶数的操作次数。那么有递推式子
b(n)=b(n-1) * (n-m)+ a(n-1) * m;
a(n)=a(n-1) * (n-m)+ b(n-1) * m;
这个构造矩阵就容易多了
ac代码:
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
struct Martix
{
    ll mp[5][5];
    int r,c;
};
ll exgcd(ll a,ll b,ll &x,ll &y)// 扩展欧几里得
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    ll temp=exgcd(b,a%b,y,x);
    y-=(a/b)*x;
    return temp;
}
ll finv(ll a,ll m)// 求逆元
{
    ll x,y;
    ll g=exgcd(a,m,x,y);
    x=(x%m+m)%m;//
    return x;
}
 long long quickmod(long long a,long long b,long long m)
{
    long long ans = 1;
    while(b)//用一个循环从右到左便利b的所有二进制位
    {
        if(b&1)//判断此时b[i]的二进制位是否为1
        {
            ans = (ans*a)%m;//乘到结果上,这里a是a^(2^i)%m
            b--;//把该为变0
        }
        b/=2;
        a = a*a%m;
    }
    return ans;
}
Martix mul(Martix a,Martix b)
{
    int r=a.r;
    int c=b.c;
    Martix temp;
    temp.r=r;
    temp.c=c;
    for(int i=0;i<r;i++)
    {
        for(int j=0;j<c;j++)
        {
            temp.mp[i][j]=0;
            for(int k=0;k<r;k++)
            {
                temp.mp[i][j]=(a.mp[i][k]*b.mp[k][j]+temp.mp[i][j])%mod;
            }
        }
    }
    return temp;
}
ll n,m;
ll pow(Martix a,ll k)
{
    Martix ans;
    ans.r=2;
    ans.c=1;
    ans.mp[0][0]=n-m;// 
    ans.mp[1][0]=m;//
    while(k)
    {
        if(k&1) ans=mul(a,ans);
        k/=2;
        a=mul(a,a);
    }
    return ans.mp[0][0]%mod;
}

int main()
{
    int t;
    ll k;
    scanf("%d",&t);
    while(t--)
    {
          scanf("%lld %lld %lld",&n,&m,&k);
          ll y=quickmod(n,k,mod);
          Martix a;
          a.r=a.c=2;
          a.mp[0][0]=a.mp[1][1]=n-m;
          a.mp[0][1]=a.mp[1][0]=m;
          ll key=pow(a,k-1);
          //cout<<key<<endl;
          ll temp=key*finv(y,mod)%mod;
          cout<<temp<<endl;
    }
    return 0;
}

 

posted @ 2017-09-16 15:41  猪突猛进!!!  阅读(262)  评论(0编辑  收藏  举报