xa=1(mod m)
存在k, xa=km+1
xa-km=1
要求a,m互质,用exgcd求x, 称a的逆元
x(mod m)
template
T exgcd(T a,T b,T &x,T &y){//这一层为x1,y1
if(b == 0){
x = 1; y = 0;
return a;
}
T d = exgcd(b, a%b, x, y);//这一层为x2,y2,下面赋值语句后面的都是修改过的值
T xt= x;//先存下x2的值,后面会修改
x = y;//x1=y2
y = xt - a / b * y;//y1=x2-a/b*y2
//此时修改后得到本层的x,y的值
return d;
}
ll mod_inverse(ll a, ll m){
ll x,y,d ;
d=exgcd(a,m,x,y);
return (x%m+m)%m; //+m保证结果为正数
在p是素数的情况下,任意x都满足 x(mod p)
如果x,p互质,则乘以x的逆元,有1 (mod p)
这又说明是x 的逆元,即 (mod p)
说明可以用快速幂求x的逆元
另外当所求的数为分数ans=需要对p取模时,用求%p即可
例题 牛客练习赛46C
有一个箱子,开始时有n个黑球,m个蓝球。每一轮游戏规则如下:
第一步:奕奕有p的概率往箱子里添加一个黑球,有(1-p)的概率往箱子里添加一个蓝球。
第二步:华华随机从箱子里取出一个球。
华华喜欢黑球,他想知道k轮游戏之后箱子里黑球个数的期望。
解题思路
设a[i]为进行了i轮游戏黑球个数的期望,则a[0]=n。
第一轮:
E(x)= n+p;
E(y)= m+q;
E(x)+E(y)=n+m+1
随机取一个,
E(x)= n+p-(n+p)/(n+m+1)= (n+p)(m+n)/(n+m+1)
E(y)= m+q-(m+q)/(n+m+1)= (m+q)(m+n)/(n+m+1)
E(x)+E(y)=n+m;
设s = (m+n)/(n+m+1);
a[1]=E(x) = ns+ps;
E(y) = ms+qs;得出结论:一轮过后a[i]=a[i-1]s+ps;
第二轮:
E(x)=ns+ps+p;
E(y)=ms+qs+q;
E(x)+E(y)= n+m+1
随机取一个....
a[2]=E(x)= a[1]s+ps;
a[0]=na[1]=s*n+p*s=n*s+p*s
a[2]=s*a[1]+p*s=n*s^2+p*s^2+p*s
a[3]=s*a[2]+p*s=n*s^3+p*s^3+p*s^2+p*s
不难得出a[k]=n*s^k+p*(s+s^1+s^2+...+s^k)
AC代码(参考题解:https://ac.nowcoder.com/discuss/191583)
#include
using namespace std;
#define ll long long
const int mod=1e9+7;
ll Mpow(ll e,ll b){
ll res=1;
while(b){
if(b&1)
res=res*e%mod;
e=e*e%mod;
b/=2;
}
return res;
}
int main()
{
int n,m,k,a,b;
scanf("%d%d%d%d%d",&n,&m,&k,&a,&b);
ll p=1LL*a*Mpow(b,mod-2)%mod;
ll s=1LL*(n+m)*Mpow(n+m+1,mod-2)%mod;
//等比数列
ll ans=1LL*n*Mpow(s,k)%mod+p*(s-Mpow(s,k+1))%mod * Mpow(1-s,mod-2)%mod;
ans=(ans%mod+mod)%mod;
printf("%lld\n",ans);
return 0;
}
如果p不是素数,分解质因数p=p1r1p2r2… 欧拉函数
φ(m)=m∏(pi-1)/pi ,是不超过m且与m互素的数的个数
如果x和m互素,有=1 mod(m)
实际上如果m是素数p, φ(m)=p-1,跟费马小定理一样的结果
欧拉函数
ll euler_phi(ll n){
ll res=n;
for(ll i=2;i*i<=n;i++){
if (n%i==0)
res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出
while(n%i==0) n/=i;
}
if (n!=1) res=res/n*(n-1);
return res;
}