牛客小白月賽9 A簽到 數論————逆元
轉自:出處
複習內容:逆元的相關知識
在開始之前我們先介紹3個定理:
1.乘法逆元(在維基百科中也叫倒數,當然是 mod p後的,其實就是倒數不是嗎?):
如果ax≡1 (mod p),且gcd(a,p)=1(a與p互質),則稱a關於模p的乘法逆元為x。
2.費馬小定理(定義來自維基百科):
如果a不是p的倍數,這個定理也可以寫成
3.
(定義來自維基百科):
已知整數a、b,擴充套件歐幾里得演算法可以在求得a、b的最大公約數的同時,能找到整數x、y(其中一個很可能是負數),使它們滿足貝祖等式。
好了,在明白上面的定理後我們開始分析乘法逆元:ax≡1 (mod p) 這個等式用中文描述就是 a乘一個數x並模p等於1,即 a%p*x%p=res,res%p=1;看上去就是同餘定理的一個簡單等式- -。那麼問題來了。
為什麼可以用費馬小定理來求逆元呢?
由費馬小定理 ap-1≡1 , 變形得 a*ap-2≡1(mod p),答案已經很明顯了:若a,p互質,因為a*ap-2≡1(mod p)且a*x≡1(mod p),則x=ap-2(mod p),用快速冪可快速求之。
為什麼可以用擴充套件歐幾里得求得逆元?
我們都知道模就是餘數,比如12%5=12-5*2=2,18%4=18-4*4=2。(/是程式運算中的除)
那麼ax≡1 (mod p)即ax-yp=1.把y寫成+的形式就是ax+py=1,為方便理解下面我們把p寫成b就是ax+by=1。就表示x是a的模b乘法逆元,y是b的模a乘法逆元。然後就可以用擴充套件歐幾里得求了。
知道逆元怎麼算之後,那麼乘法逆元有什麼用呢?
做題時如果結果過大一般都會讓你模一個數,確保結果不是很大,而這個數一般是1e9+7,而且這個數又是個素數,加減乘與模運算的順序交換不會影響結果,但是除法不行。有的題目要求結果mod一個大質數,如果原本的結果中有除法,比如除以a,那就可以乘以a的逆元替代。(除一個數等於乘它的倒數,雖然這裡的逆元不完全是倒數,但可以這麼理解,畢竟乘法逆元就是倒數的擴充套件)。
#include<bits/stdc++.h> using namespace std; typedef long long ll; void exgcd(ll a,ll b,ll& d,ll& x,ll& y) { if(!b) { d = a; x = 1; y = 0; } else{ exgcd(b, a%b, d, y, x); y -= x*(a/b); } } ll inv(ll a, ll p) { ll d, x, y; exgcd(a, p, d, x, y); return d == 1 ? (x+p)%p : -1; } int main() { ll a,p; while(1) { scanf("%lld %lld",&a,&p); printf("%lld\n",inv(a,p)); } }
題目描述
你在一棟樓房下面,樓房一共有n層,第i層每秒有pi的概率會扔下一個東西並砸到你
求第一秒內你被砸到的概率
輸入描述:
第一行一個整數n 之後有n行,第i+1行有兩個整數ai,bi,表示
輸出描述:
設答案為,你只需要找到一個最小的非負整數T,使得 輸出這個T就行了
示例1
輸入
2 1 2 1 2
輸出
750000006
說明
一共只有如下狀態: 1. 第一層和第二層都扔了下來 2. 第一層扔了下來 3. 第二層扔了下來 4. 第一層和第二層都沒有扔下來 以上四種都是等概率發生的 除了第四種情況外,都會被砸到 因此被砸到的概率是 3/4,這個值在模1e9+7意義下就是750000006
備註:
資料範圍 0 ≤ n ≤ 105 1 ≤ ai ≤ bi ≤ 105
此程式碼為學長的,自己的程式碼總是不對,就一點一點改,到頭來忘了取模了。小辣雞“”“”“”“”“”
#include<bits/stdc++.h>
using namespace std;
int mod=1e9+7;
typedef long long ll;
inline ll pow_mod(ll n,ll k)//n^k%mod
{
ll res=1;
n=n%mod;
while(k>0)
{
if(k&1)
res=res*n%mod;
n=n*n%mod;
k>>=1;
}
return res;
}
int main()
{
ll n,p=1,q=1,a,b;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a,&b);
p=p*(b-a)%mod;
q=q*b%mod;
}
ll ans=((q-p+mod)*pow_mod(q,mod-2))%mod;
printf("%lld\n",ans);
return 0;
}
同上:不用看
#include<bits/stdc++.h>
using namespace std;
int mod=1e9+7;
typedef long long ll;
inline ll pow_mod(ll n,ll k)//n^k%mod
{
ll res=1;
n=n%mod;
while(k>0)
{
if(k&1)
res=res*n%mod;
n=n*n%mod;
k>>=1;
}
return res;
}
int main()
{
ll n,a=1,b=1,a1,b1;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a1,&b1);
a=a*(b1-a1)%mod;
b=b*b1%mod;
}
ll temp=b-a+mod;
printf("%lld\n",((temp*pow_mod(b,(mod-2)))%mod));
return 0;
}