逆元的定義
逆元 (Inverse element) 就是在 mod 意義下,不能直接除以一個數,而要乘以它的逆元。
比如 a ∗ b ≡ 1 (mod p),那麼 a,b 互爲模 p 意義下的逆元,比如你要算 x / a % p,就可以改成 x * b % p 。
求逆元有很多方法,請看下面!
方法一:費馬小定理 / 歐拉定理
費馬小定理: 若 p 爲素數,則有
即
則 就是 a 在 mod p 意義下的逆元
歐拉定理: 若 a、p 互素,則有 (費馬小定理的一般形式)
得
故 就是 a 在 mod p意義下的逆元
性能分析:
適用範圍:一般在 mod 是個素數的時候用,比擴展歐幾里得方法快一點而且好寫。
Code:
ll q_pow(ll a,ll b,ll mod){
ll ans=1,res=a%mod;
while(b){
if(b&1) ans=ans*res%mod;
res=res*res%mod;
b>>=1;
}
return ans%mod;
}
ll inv(ll a,ll mod){
return q_pow(a,mod-2,mod)%mod;
}
經典例題
例題1:http://poj.org/problem?id=1845
題意: 給定兩個正整數 A 和 B ,求 的所有因子和對9901取餘後的值。
例題2: https://www.lydsy.com/JudgeOnline/problem.php?id=2186
題意: 求 1 到 N! 中與 M! 互質的數的個數,其中 M <= N 。
例題3: http://codeforces.com/contest/964/problem/C
題意:
例題4: https://ac.nowcoder.com/acm/contest/3005/C
思路: 這裏用尺取法 + 逆元來做。l 代表左端點,r 代表右端點。l 先不動,r 往前掃描,如果成功掃到,有 k 個非0元素的子段就累乘起來,最後把最左端的元素除了(用乘法逆元,否則會出現除以 0 的異常),左端點往前移動,l++,再繼續掃描。在未達到 k 個非零元素的子段前,如果遇到 0,當前的區間重置 ,左端點直接到 0 的下一個位置繼續掃描。
#include <iostream>
using namespace std;
typedef long long ll;
const int N=2e5+100;
const ll mod=998244353;
int n,k;
ll a[N];
ll q_pow(ll a,ll b){
ll ans=1,res=a%mod;
while(b){
if(b&1) ans=ans*res%mod;
res=res*res%mod;
b>>=1;
}
return ans%mod;
}
ll inv(ll a,ll mod){
return q_pow(a,mod-2)%mod;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
int l=1,r=1;
ll mul=1,ans=0;
while(r<=n){
if(a[r]){
mul=mul*a[r]%mod;
if(r-l+1==k){
ans=max(ans,mul);
mul=mul*inv(a[l],mod)%mod;
l++;
}
}
else{
mul=1;
l=r+1;
}
r++;
}
cout<<ans<<endl;
return 0;
}