尚无万分品质,模13含义下5的逆元是8……

 

 

710官方网站,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。

接纳高效幂及扩大欧几Reade算法求逆金朝码如下:

 

 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 }

个体了然

对此个人的知情逆元,逆元是在运算除时,能够改为乘,方便统计,像上面一样,a/b(mod
p)就可以变成a*b-1,那也等于逆元的精神,必须要在的意思下才使得。

运算a/b时,我们除以b就约等于乘以1/b,那是个分数,不便宜总计,所以大家就找到了三个整数,b的逆元,比如总括12/3(mod
7),那是个除法,所以大家可以那样12*(33.33%),尽管是乘法了,可是有分数,所以找八个整数使得x,3x≡1(mod
7),x=5,即模7意义下3的逆元是5,然后我们倍加那么些逆元,12*5 = 60,60 mod
7 = 4,诶,12/3 = 4,相等啊,那就是地点所说的习性,

 

 洛谷 P3807【模板】Lucas定理

难点叙述

给定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表示组合数。

1个测试点内包括多组数据。

输入输出格式

输入格式:

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

其次行开端共T行,每行七个数n
m p,意义如上

输出格式:

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

输入输出样例

输入样例#1:
复制

2
1 2 5
2 1 5

输出样例#1:
复制

3 3

与zqsz的互测题 T1 原题 POJ 1845

应用

大家了然(a+b)%p = (a%p+b%p)%p

    (a*b)%p = (a%p)*(b%p)%p

求(a/b)%p时,可能会因为a是二个非常的大的数,不可以一向算出来,也无能为力像上边一样分解。

咱们得以经过求b关于p的乘法逆元k,k ≡ b-1 (mod p)
,将a乘上k再模p,即(a*k) mod p。其结果与(a/b) mod p等价。

下一场那就成了求a*k%p,然后就可以用那多少个公式了。

代码:

 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 }

 


存在性

看起来和同余方程很相似(其实上面真的可以用exgcd求的!),在同余方程中

ab ≡ 1(mod p)

若a 与p 互质, 则一定存在三个正整数解b, 满意b < p,若a 与p 不互质,
则一定不存在正整数解b.

所以逆元必要a与p互质

代码:

 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 }
【题目描述】

谜团,是夜魇军团一名强大的战士。他来自远古,是一种不可思议的重力生命体,是来自原始黑暗的扭曲声音,在宇宙中的第一丝光线诞生前就存在的深渊化身。他能动用深渊之力将生物的身体污染,使之转化为自身的碎片“虚灵”。

“虚灵”为谜团所控,拥有一定的战斗力。更为恐怖的是,新产生的“虚灵”的 第一次攻击将吸收被攻击者内心的黑暗,从而分裂成若干个“虚灵”,之后的攻击将无法产生“虚灵”,新产生的“虚灵”第一次攻击仍可产生“虚灵”。 作为天辉军团智囊的你,需要知道某一时刻谜团最多可以产生多少“虚灵”,从而据

此来进行决策。具体的,谜团在 第一秒会转化一个单位,使之变成一个“虚灵”,由于能量消耗过大,谜团在之后的时间内将不再转化单位,使之变成“虚灵”。新产生的“虚灵”会在**下一秒**攻击一次,从而分裂出 m 个“虚灵”,原有的“虚灵”仍然存在,并且将不再产生虚灵。但新产生的“虚灵”可在下一秒攻击一次并分裂,之后也将不再产生“虚灵”(具体见样例解释)。给定时间 t 和分裂数 m,请你告诉天辉军团的战士们,在 t 秒后,谜团拥有多少个“虚灵”。

答案可能很大,要求你模一个数 k(不保证 k 是质数)。


【输入格式】

第一行:三个整数 m,t,k,意义见题目描述

【输出格式】

第一行:t 秒后谜团拥有的能量体个数

【样例输入 1】

3 3 1000

【样例输出 1】

13

【样例输入 2】

3 5 1000

【样例输出 2】

121

【样例 1 解释】

m = 3, t = 5 时:

第一秒:谜团制造 1 个“虚灵”

第二秒:1 个“虚灵”分裂出 3 个“虚灵”,此时共有 4 个“虚灵”

第三秒:第 1 秒制造的 1 个“虚灵”将不能分裂,第 2 秒制造的 3 个“虚灵”,

每个“虚灵”分裂成 3 个“虚灵”,新分裂出的“虚灵”有 9 个,此时共有 13

个“虚灵”。

最终,总共有 13 个“虚灵”

【数据规模与约定】

保证 k,m,t 及答案在 int 范围内(注意只有答案!!!)



原题意是求A^B的约数个数,因为出题人很良心(原话),所以就改为求首项为1,公比为m的等比数列的前n项和。

 部分分

定义

乘法逆元的概念:若存在正整数a,b,p, 满足ab = 1(mod p), 则称a 是b
的乘法逆元, 或称b 是a 的乘法逆元。b ≡ a-1 (mod p),a ≡
b-1 (mod p)

例如, 在模7 意义下,3 的乘法逆元是5, 也得以说模7
意义下5的乘法逆元是3。模13意义下5的逆元是8……

Solution:

求解线性同余方程,直接可以套上增添欧几Reade的沙盘。a*x≡c
mod(b) 等同于 a*x+b*y=c ,有整数解的需要条件是:c%GCD(a,b)=0
。那么那道题就是在求a*x+b*y=1中x的最小解(越发的当a,b互质时,x为a的逆元)。扩欧作者就不赘述了。

1~8 暴力枚举 

二 、线性求逆元

先校正一下变量名,再改回来ab = 1(mod p),求b

p%a = p-(p/a)*a;  在c++中/为整除。

(p/a)*a = p-(p%a);  换下地点

(p/a)*a = -(p%a);  在模p意义下p可以约掉,能够没有这一步

a = -(p%a)/(p/a);  再换一下地方

a-1 = -(p%a)-1*(p/a);

所以a-1可以用(p%a)-1推出,所以就足以用递推式来生产1到a的全部数的逆元。

代码

710官方网站 1710官方网站 2

1 int inv[MAXN]; 
2 void INV(int a,int p)//线性求到a的逆元 
3 {
4     inv[1] = 1;
5     for (int i=2; i<=a; ++i)
6         inv[i] = (-(p/i))*inv[p%i]%p; 
7 }

线性求逆元1

下边的代码只求1个值的逆元,运用的是下面的姿势

710官方网站 3710官方网站 4

1 int INV(int a)//线性求a的逆元 
2 {
3     if (a==1) return 1;
4     return ((-(p/a)*INV(p%a))%p);
5 }

线性求逆元2

输入输出样例

输入样例#1: 

3 10

出口样例#1: 

7

叁 、欧拉定理求逆元

欧拉定理:aφ(p) ≡ 1(mod p)

对于随意互质的a,p 恒创制。

欧拉定理用来求逆元用的是欧拉定理的五个推测:
a*aφ(p)-1 ≡ 1(mod p

有心人考察,a*b ≡ 1(mod
p),在那边的b不就是地点的aφ(p)-1呢?,所以求出aφ(p)-1就好了。

故而大家用便捷幂就足以求出乘法逆元了。

其一措施它必要多算贰个欧拉函数,代码那里不再给出。

补充:其实假诺p是质数的话,可以用费马小定理,与欧拉定理是一心平等的,费马小定理在p不是质数时,则不得不用欧拉定理。

怎么弄呢?费马小定理 a(p-1) ≡ 1(mod p)
p是质数,且a,p互质,

下一场将方面的姿态变一下,a*a(p-2) ≡ 1(mod p) ,

再变一下,a(p-2) 
a-1 (mod p)
,然后求出a(p-2)就足以了。

然后再看一下欧拉定理,假诺p是质数,φ(p) =
p-1,那么大家求aφ(p)-1,约等于求a(p-2)。和费马小定理是均等的。

 洛谷 P1082 同余方程


壹 、增添欧几里得

可以用扩张欧几里得求,那么是怎么个求法呢?

恢宏欧几里得是用来求那样的一组解的:ax+by =
gcd(a,b),求x和y,(求出x后当然驾驭了y,所以算是求3个x)。

逆元呢是求那样的二个解:ax ≡ 1 (mod
b),(为了有利于清楚,改了一晃变量名),求x,貌似并不曾一点点形似处,那么大家变一下,

ax+by = gcd(a,b),变成 ax+by = c;

ax ≡ 1 (mod b),变成 ax-by = 1;如若将y看成负的,ax+by = 1;

一心平等嘛,所以直接套用扩充欧几里得求就好了。

代码

710官方网站 5710官方网站 6

 1 #include<cstdio>
 2 
 3 int exgcd(int a,int b,int &x,int &y)
 4 {
 5     if (b==0)
 6     {
 7         x = 1;
 8         y = 0;
 9         return a;
10     }
11     int r = exgcd(b,a%b,x,y);
12     int tmp = x;
13     x = y;
14     y = tmp-a/b*y;
15     return r;
16 }
17 
18 int main()
19 {
20     //gcd(a,p)==1
21     int a,p,r,x,y;
22     while (scanf("%d%d",&a,&p)!=EOF)
23     {
24         r = exgcd(a,p,x,y);
25         printf("%d",(x%p+p)%p);
26     }
27     return 0;
28 }

增加欧几里得求逆元

输入输出格式

输入格式:

输入唯有一行,包蕴七个正整数
a, b,用二个空格隔开。

出口格式:

出口唯有一行,包括二个正整数
x0,即最小正整数解。输入数据有限支撑一定有解。

*PS: 没开long long被卡掉45分,果然出题人的话都不可信QAQ。。(学傻了)

求法

求逆元有两种求法,

输入输出格式

输入格式:

一行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为质数。

17~20 没有新鲜属性

难题叙述

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

正解 2 二分+递归

数学课上的求等比数列的前n项和有一个公式,emmm,公式有很多的变形,其中有一个变形为

710官方网站 7

若另 n 和 m 都等于 t/2 ,可知 


所以我们要求St,只需要每次二分的递归下去,在递归的过程中取模就可以了。

另外注意递归的时候要分t为奇数和偶数的情况,因为计算机里的/是会自动下取整的。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define ll long long
 7 
 8 ll M,T,K;
 9 
10 ll pow(ll a,ll n)
11 {
12     ll sum=1,x=a;
13     while(n)
14     {
15         if(n&1) sum=sum%K*x%K%K;
16         x=x%K*x%K%K;
17         n>>=1;
18     }
19     return sum;
20 }
21 
22 ll sum(ll q,ll t) // q^0+q^1+q^2+...+q^t --> S(t+1)
23 {
24     if(t==0) return 1;
25     if(t%2==0) return (sum(q,t/2-1)%K*(1+pow(q,t/2))%K%K+pow(q,t)%K)%K; 
26     //t 为偶数,说明S(t+1)没法直接通过S((t+1)/2)求得,就去求St,最后加上一个q^t次方 
27     else return (sum(q,t/2)%K*(1+pow(q,t/2+1))%K)%K; 
28     //t 为奇数,说明S(t+1)可以直接用(S(t+1)/2)求得,又S((t+1)/2)即为sum(q,t/2)(t/2下取整),可以直接求 (t/2+1即为(t+1)/2)  
29 }
30 int main()
31 {
32     freopen("mituan.in","r",stdin);
33     freopen("mituan.out","w",stdout);
34     scanf("%d%d%d",&M,&T,&K);
35     printf("%lld",sum(M,T-1));
36     return 0;
37 }

 

 

 

 

洛谷 P3811 【模板】乘法逆元

9~12 特殊性质:模数k是质数,因为等比数列的前n项和为 q^n-1/(q-1),除法的取模需要用到逆元,可以用费马小定理做。

a^(p-1) ≡ 1(mod p) ---> a^(p-2) ≡ 1/a (mod p)

1 ll ans=(multiply(T,M)-1)%K*multiply(K-2,M-1)%K%K;
2 printf("%lld",ans);

说明

【数据范围】

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

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

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

NOIP 2012
提高组 第二天 第一题

正解 1 公式求逆元

安利多个事先看来的博客(为啥本人顿风尚未出色看qwq)

http://blog.csdn.net/acdreamers/article/details/8220787

因为费马小定理和扩大欧几里得算法求逆元是有局限性的,它们都会须要a与m互素。

只是我们有1个公式,若
b|a , 则ans即为(a/b)mod m 的答案:

 

710官方网站 8

证明:

(a/b)mod m = ans

a/b = ans + k * m

a = ans * b + k * m
* b ;

a mod ( bm ) = ans * b

a mod ( bm ) / b = ans

得证。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 #define ull unsigned long long 
 8 
 9 ull M,T,K;
10 
11 ull multiply(ull n,ull a)
12 {
13     ull sum=1,x=a;
14     while(n)
15     {
16         if(n&1) sum=sum%K*x%K%K;
17         x=x%K*x%K%K;
18         n>>=1;
19     }
20     return sum%K;
21 }
22 int main()
23 {
24     freopen("mituan.in","r",stdin);
25     freopen("mituan.out","w",stdout);
26     scanf("%lld%lld%lld",&M,&T,&K);
27     K=K*(M-1);
28     ull ans=(multiply(T,M)-1)/(M-1);
29     printf("%lld",ans);
30     return 0;
31 }

 


 

难题叙述

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

13~16(原话)特殊性质 k不是质数,但k与m互质,用扩展欧几里得求逆元。

但是,我用的扩展欧几里得是要求m-1在%k意义下的逆元啊喂!! 没有给部分分QAQ。

直接打exgcd可以的50分,前提是你开了long long ,但是我并没有开qwqqqq(让我自己一个人静一会)。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 long long M,T,K,ans;
 9 
10 long long multiply(long long n,long long a)
11 {
12     long long sum=1,x=a;
13     while(n)
14     {
15         if(n&1) sum=sum%K*x%K%K;
16         x=x%K*x%K%K;
17         n>>=1;
18     }
19     return sum%K;
20 }
21 long long exgcd(long long a,long long b,long long &x,long long &y)
22 {
23     if(b==0)
24     {
25         x=1,y=0;
26         return a;
27     }
28     long long d=exgcd(b,a%b,y,x);
29     y=y-a/b*x;
30     return d;
31 }
32 int main()
33 {
34     freopen("mituan.in","r",stdin);
35     freopen("mituan.out","w",stdout);
36     scanf("%lld%lld%lld",&M,&T,&K);
37     {
38         long long x,y;
39         long long d=exgcd(M-1,K,x,y);
40         x%=K;
41         while(x<0) x+=K/d;
42         ans=(multiply(T,M)-1)%K*x%K%K;
43         if(ans<0) ans+=K;
44         printf("%lld",ans);
45     }
46     return 0;
47 }

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(很好精晓,不做解释)。



相关文章