题目:click
题意:有三个杯子,钥匙一开始在中间,n轮游戏,每一轮游戏可以选择一个杯子与中间的交换,问n轮钥匙要中间的概率。用分数表示。
1. 有点类似概率dp的味道,但不需要你计算机跑,手算递推就可以了。
dp[i]为第i轮钥匙在中间的概率,那么dp[i]=(1-dp[i-1])/2;
很明显dp[1]=0;进行公式展开n项递推,
所得的概率为
2
n
−
1
−
(
−
1
)
n
−
1
3
∗
2
n
−
1
\frac{2^{n-1}-(-1)^{n-1}}{3*2^{n-1}}
3∗2n−12n−1−(−1)n−1
但n等于
∏
\prod
∏a[i] ,先利用欧拉定理计算
2
n
−
1
2^{n-1}
2n−1,
可以发现我一定需要使用快速幂中加mod,不然无法计算,这么计算我一定要找到满足条件的分子分母互质才可以如此计算。
扩展欧几里德除法可知 x>=2 x与x-1 x与x+1互质。
2
n
−
1
−
(
−
1
)
n
−
1
2
n
−
1
\frac{2^{n-1}-(-1)^{n-1}}{2^{n-1}}
2n−12n−1−(−1)n−1即这个等式的分子分母互质。
gcd()=1,但是发现还有一个3并没有处理,3需要处理,判断分子与3的关系,可以证明。
n=1的时候一定成立,数学归纳法证明一下就可以了。发现
2
n
−
1
−
(
−
1
)
n
−
1
3
\frac{2^{n-1}-(-1)^{n-1}}{3}
32n−1−(−1)n−1可以整除结果为(2*k-
(
−
1
)
n
(-1)^{n}
(−1)n)而且一定是一个奇数,但是
2
n
−
1
2^{n-1}
2n−1只有因子2,奇数因子并没有2,互质。完成了,1/3mod 的时候利用一下费马小定理计算。
2. 网上看到了一个巨巨使用dp加矩阵快速幂解决了,也是一个思路。
原矩阵快速幂思路:click
直接利用p/q作为基值进行递推,p[i]/q[i]=(q[i-1]-p[i-1])/(q[i-1]2);
为什么是对的?这里可以简单的证明一下,n=1的时候等于0没有问题,而每次得到的q[i]必定是一个偶数2q[i-1]对吧,q[i-1],p[i-1]要互质那么p[i-1]必定是一个奇数,那么q[i-1]-p[i-1]仍然为奇数,奇数比一个因子只有2的偶数必互质。题目中也似乎考虑到这一点给的是0/1作为n=1的基值。
找到矩阵{{-1 1},{0,2} }。
由于解出的是p[n+1],q[n+1]之后反解。
如:(2^(n-1)*2)%mod=x 反解 2^(n-1)%mod
给出两种方法的代码:
1.
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll a[100100];
ll dp[100100];//第i次操作钥匙在中间的概率 dp[i]=(1-dp[i-1])/2
ll quickpow(ll a,ll n)
{
ll res=1;
while(n)
{
if(n&1)
{
res=(res*a)%mod;
}
n>>=1;
a=(a*a)%mod;
}
return res%mod;
}
ll gcd(ll a,ll b)
{
if(!b)
return a;
else
return gcd(b,a%b);
}
int main()
{
ll n,i,j;
scanf("%I64d",&n);
ll ans=1;
ll uuu;
ll fh=1;
for(i=0;i<n;i++)
{
scanf("%I64d",&a[i]);
a[i]%=(mod-1);//注意a[i]的范围 防止 a[i]*ans时直接爆精度
if(a[i]%2==0)
{
fh=0;
}
ans=((ans*a[i])%(mod-1));
}
ans=quickpow(2,(ans-1+mod-1));
ll temp1=quickpow(3,mod-2);
ll hh;
if(fh)
hh=-1;
else
hh=1;
ll t2=(((ans+hh)%mod)*temp1)%mod;
printf("%I64d/%I64d",t2,ans);
return 0;
}
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll a[100100];
typedef struct A {
ll m[2][2];
void Matrixclear()
{
m[0][0]=1;
m[0][1]=0;
m[1][0]=0;
m[1][1]=1;
}
}Matrix;
Matrix p;
Matrix matrixmul(Matrix t1,Matrix t2)
{
Matrix temp;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
temp.m[i][j]=0;
for(int k=0;k<2;k++)
{
temp.m[i][j]+=t2.m[k][j]*t1.m[i][k];
temp.m[i][j]%=mod;
}
}
}
return temp;
}
Matrix quickpow(Matrix a,ll n)
{
Matrix hh;
hh.Matrixclear();
while(n)
{
if(n&1)
{
hh=matrixmul(hh,a);
}
a=matrixmul(a,a);
n>>=1;
}
return hh;
}
int main()
{
p.m[0][0]=-1,p.m[0][1]=1,p.m[1][0]=0,p.m[1][1]=2;
ll n,i,j;
scanf("%I64d",&n);
ll fh=1;
ll yy=2;
for(i=0;i<n;i++)
{
scanf("%I64d",&a[i]);
p=quickpow(p,a[i]);
}
ll t1=p.m[0][1];
ll t2=p.m[1][1];
if(t2%2==0)
t2/=2;
else
t2=(t2+mod)/2;
ll q=(t2)%mod;
ll p=(q-t1+mod)%mod;
printf("%I64d/%I64d",p,q);
return 0;
}