710官方网站~n中有着整数在模p意义下的乘法逆元,~n中装有整数在模p意义下的乘法逆元

luogu P3811 【模板】乘法逆元

洛谷 P3811 【模板】乘法逆元

题材背景

那是一道模板题

标题背景

那是一道模板题

标题叙述

给定n,p求1~n中存有整数在模p意义下的乘法逆元。

问题叙述

给定n,p求1~n中全部整数在模p意义下的乘法逆元。

题材叙述

给定n,p求1~n中具备整数在模p意义下的乘法逆元。

输入输出格式

输入格式:

一行n,p

输出格式:

n行,第i行表示i在模p意义下的逆元。

输入输出样例

输入样例#1: 

10 13

出口样例#1: 

1
7
9
10
8
11
2
5
3
4

说明

1≤n≤3×106,n<p<20000528

输入保障p为质数。

输入输出格式

输入输出格式

输入格式:

 

一行n,p

 

出口格式:

 

n行,第i行代表i在模p意义下的逆元。

 

Solution:

第二大家来询问一下逆元。

若a*x≡1(mod
b),a、b互质,则称x为a的逆元,记为a-1。依据逆元的概念,可转化为a*x+b*y=1,用扩张欧几Reade法求解。逆元能够用来在测算(t/a)mod
b时,转化为t*a-1mod
b。

使用高效幂及增加欧几里德算法求逆曹魏码如下:

 

 1 void exgcd(int a,int b,int &x,int &y){
 2     if(a==0){x=0;y=1;return;}
 3     else {
 4         int tx,ty;
 5         exgcd(b%a,a,tx,ty);
 6         x=ty-(b/a)*tx;
 7         y=tx;
 8         return;
 9     }
10 }

 

求逆元还有四个线性算法,具体进程如下。

首先,1-1≡1(mod
p)。

然后,我们设p=k*i+r,r<i,1<i<p,再将这一个姿势放到mod
p意义下就会获得:k*i+r≡0(mod
p)

再两边同时乘上i-1、r-1就会收获:

k*r-1+i-1≡0(mod
p)     –>   i-1≡-k*r-1(mod p)    –>   
i-1≡-[p/i]*(p mod i)-1 (mod
p)

于是,就能够在此以前边推出当前的逆元。代码也就一行:a[i]=-(p/i)*a[p%i];

下一场那道模板题,正是用上述措施解决的。。

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define il inline
 5 #define inf 233333333333
 6 ll n,p,a[3000600],b;
 7 int main()
 8 {
 9     scanf("%lld%lld",&n,&p);
10     a[1]=1;
11     for(int i=2;i<=n;i++){
12     a[i]=-(p/i)*a[p%i];
13     while(a[i]<0)a[i]+=p;
14     printf("%lld\n",a[i-1]);
15     }
16     printf("%lld\n",a[n]);
17     return 0;
18 }

输入格式:

 

一行n,p

 

输入输出样例

输入样例#1: 复制

10 13

出口样例#1: 复制

1
7
9
10
8
11
2
5
3
4

 洛谷 P3807【模板】卢卡斯定理

题材叙述

给定n,m,p(1≤n,m,p≤1051\le n,m,p\le
10^51≤n,m,p≤105)

求 Cn+mm mod pC_{n+m}^{m}\ mod\
pCn+mm​ mod p

保证P为prime

C表示组合数。

多个测试点内包罗多组数据。

输入输出格式

输入格式:

率先行三个整数T(T≤10T\le 10T≤10),表示数据组数

其次行伊始共T行,每行多个数n
m p,意义如上

输出格式:

共T行,每行八个整数表示答案。

输入输出样例

输入样例#1:
复制

2
1 2 5
2 1 5

出口样例#1:
复制

3 3

输出格式:

 

n行,第i行表示i在模p意义下的逆元。

 

说明

1 ≤ n ≤ 3*106, n < p <
20000528 1≤n≤3×106,n<p<20000528

输入保障 pp 为质数。

(1)连忙幂+费马小定理(nlogp)[常数较大]

#include<cstdio>
#include<iostream>
#include<algorithm>
#define LL long long
#define FOR(i,s,t) for(register int i=s;i<=t;i++)
using namespace std;
int n,p;
inline LL Fast_Power(int a,int b){
    if(b==0)
        return 1;
    if(b==1)
        return a;
    LL ans=Fast_Power(a,b>>1);
    ans=(ans*ans)%p;
    return b&1?(ans*a)%p:ans; 
}
int main(){
    scanf("%d%d",&n,&p);
        FOR(i,1,n)
            printf("%lld\n",Fast_Power(i,p-2));
    return 0;
}

(2)exgcd求线性方程[常数较小]

#include<cstdio>
#include<iostream> 
#include<vector>
#include<algorithm>
#include<cmath>
#define BIG 100011 
#define ll long long
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
using namespace std;
ll ansx,ansy,n,p;
inline ll exgcd(ll a,ll b,ll &x,ll &y){
    if(!b)
        return a,x=1,y=0;
    ll s=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return s;
}
int main(){
    cin>>n>>p;
    FOR(i,1,n){
        exgcd(i,p,ansx,ansy);
        printf("%lld\n",(ansx+p)%p);
    }
    return 0;
} 

(3).线性算法O(n)

递推式 f[i]=p-p/i*f[p%i]%p.

 证明:

pΞk*i+r(mod p)

k*i+rΞ0(mod p)

同乘 i-1*r-1

k*r-1+i-1Ξ0 (mod
p)

i-1Ξ-k*r-1(mod
p)

f[i]=p-p/i*f[p%i]%p.

#include<cstdio>
#include<iostream> 
#include<vector>
#include<algorithm>
#include<cmath>
#define BIG 100011 
#define ll long long
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
using namespace std;
ll n,p;
ll f[3000011];
int main(){
    cin>>n>>p;
    f[1]=1;
    puts("1");
    FOR(i,2,n){
        f[i]=(p-p/i)*f[p%i]%p;
        printf("%lld\n",f[i]);
    }
    return 0;
} 

 

  

 

Solution:

Lucas定理。

就是C(n,m) mod
p=C(n%p,m%p)*C(n/p,m/p)%p。

评释:不会。记着就行。(×)

代码达成地点,注意两点:

1.对于​C(n/p,m/p)部分能够持续运用Lucas定理递归求解。

2.求逆元,能够用费马小定理做快捷幂,当然也可以线性预处理阶乘逆元。注意,若线性预处理,须求将000位赋位111(很好明白,不做解释)。

输入输出样例

输入样例#1: 复制

10 13

出口样例#1: 复制

1
7
9
10
8
11
2
5
3
4

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define il inline
 5 ll n,m,p,a[100005],b[100005];
 6 il ll gi()
 7 {
 8     ll a=0;char x=getchar();bool f=0;
 9     while((x<'0'||x>'9')&&x!='-')x=getchar();
10     if(x=='-')x=getchar(),f=1;
11     while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
12     return f?-a:a;
13 }
14 il ll fast(ll n,ll m,ll p)
15 {
16     if(m>n)return 0;
17     return a[n]*b[n-m]%p*b[m]%p;
18 }
19 il ll lucas(ll n, ll m ,ll p)
20 {
21     if(!m)return 1;
22     return fast(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
23 }
24 int main()
25 {
26     int t=gi();
27     while(t--)
28     {
29         a[0]=b[0]=a[1]=b[1]=1;
30         n=gi(),m=gi(),p=gi();
31         n+=m;
32         for(int i=2;i<=p;i++)b[i]=-(p/i)*b[p%i]%p;
33         for(int i=2;i<=p;i++)a[i]=a[i-1]*i%p,b[i]=b[i-1]*b[i]%p;
34         printf("%lld\n",(lucas(n,m,p)+p)%p);
35     }
36     return 0;
37 }

说明

1 \leq n \leq 3 \times
10 ^ 6, n < p < 200005281≤n≤3×106,n<p<20000528

输入保障 pp 为质数。

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
const int N = 3e6 + 10;

#define LL long long
#define lgj 1000000007

LL jc[N], inv[N], Inv[N];
LL n, k;

inline LL read(){
    LL x = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x;
}

void exgcd(LL a, LL b, LL & x, LL & y){
    if(!b){
        x = 1;
        y = 0;
        return ;
    }
    exgcd(b, a % b, x, y);
    LL tmp = x;
    x = y;
    y = tmp - a / b * y; 
}

inline void work_1(){
    LL x, y;
    exgcd((jc[k] * jc[n - k]) % lgj, lgj, x, y);
    while(x < 0) x += lgj;
    LL answer = (jc[n] * x) % lgj;
    printf("%lld", answer);
    exit(0);
}

inline LL ksm(LL x, LL y){
    LL ret = 1;
    while(y){
        if(y & 1) ret = ret * x % lgj;
        x = x * x % lgj;
        y >>= 1;
    }
    return ret;
}

inline void work_2(){
    LL x = ksm((jc[k] * jc[n - k]) % lgj, lgj - 2);
    LL answer = (jc[n] * x) % lgj;
    printf("%lld", answer);
    exit(0); 
}

inline void work_3(){
    inv[1] = inv[0] = 1; Inv[0] = Inv[1] = 1;
    for(int i = 2; i <= n; i ++)
    {
        inv[i] = (1LL * (- (lgj / i)) * inv[lgj % i]) % lgj;
        if(inv[i] < 0) inv[i] += lgj;
        Inv[i] = (Inv[i - 1] % lgj * inv[i] % lgj) % lgj;
        if(Inv[i] < 0) Inv[i] += lgj;
    }    
    LL answer = ((jc[n] % lgj * Inv[k] % lgj) % lgj * Inv[n - k] % lgj) % lgj;
    printf("%lld", answer);
}

inline void work_4(){

    inv[1] = inv[0] = 1;
    for(int i = 2; i <= n; i ++)
    {
        inv[i] = ((1LL * (- (k / i))) * inv[k % i]) % k;    
        if(inv[i] < 0) inv[i] += k;
    } 
}

int main()
{
    n = read();
    k = read();
    jc[1] = 1;
    for(int i = 2; i <= n; i ++) jc[i] = (jc[i - 1] * (i % lgj)) % lgj;
    //work_1();//exgcd 
    //work_2();//ksm
    //work_3();//线性求逆元 inv[i] i 在 % lgj 意义下的逆, Inv[i] 阶乘的逆,也就是将逆阶乘
    work_4();
    for(int i = 1; i <= n; i ++) printf("%lld\n", inv[i]);
    return 0;
}

 

 洛谷 P1082 同余方程

题材叙述

求关于 x
的同余方程 ax ≡ 1 (mod b)的细微正整数解。

输入输出格式

输入格式:

输入唯有一行,包蕴四个正整数
a, b,用3个空格隔绝。

输出格式:

输出只有一行,包罗一个正整数
x0,即最小正整数解。输入数据有限支撑一定有解。

输入输出样例

输入样例#1: 

3 10

出口样例#1: 

7

说明

【数据范围】

对于
40%的数据,2 ≤b≤ 1,000;

对于
60%的数据,2 ≤b≤ 50,000,000;

对于
100%的数据,2 ≤a, b≤ 2,000,000,000。

NOIP 2012
提高组 第二天 第一题

Solution:

求解线性同余方程,直接能够套上扩充欧几Reade的模板。a*x≡c
mod(b) 等同于 a*x+b*y=c ,有整数解的须求条件是:c%GCD(a,b)=0
。那么那道题便是在求a*x+b*y=第11中学x的最小解(尤其的当a,b互质时,x为a的逆元)。扩欧作者就不赘述了。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define il inline 
 5 il void exgcd(int a,int b,int &x,int &y)
 6 {    
 7     if(!b){x=1,y=0;return;}
 8     exgcd(b,a%b,x,y);
 9     int t=x-a/b*y;
10     x=y;y=t;
11     return;
12 }
13 int a,b,x,y;
14 int main()
15 {
16     scanf("%d%d",&a,&b);
17     exgcd(a,b,x,y);
18     while(x<0)x+=b;
19     cout<<x;
20     return 0;
21 }

 

相关文章