sdx-暑期总结2

同余定理

(a + b) % m = (a % m + b % m) % m

(a * b) % m = ((a % m) * (b % m)) % m

在前面的快速幂中用到。以及在高精度取模中用到。

高精度取模即把高精度数看成各位数的权值与个位数乘积的和。

    比如1234 = ((1 * 10 + 2) * 10 + 3) * 10 + 4,对这个数进行取余运算就是上面基本加和乘的应用。

代码如下

#include
#include
#include
using namespace std;
 
int main(){
    string a;//把数用字符存起来
    int b;
    cin >> a >> b;
    int len = a.length();
    int ans = 0;
    for(int i = 0; i < len; i++){
        ans = (ans * 10 + a[i] - '0') % b;//同余定理
    }
    printf("%d\n",ans);
    return 0;
}

 

逆元

对于整数a,p,若存在一个整数x,使ax≡1 (mod p)ax%p=1成立,则称x是a对p的逆元(当且仅当gcd(a,p)=1时,才存在且存在唯一逆元),我们用inv(a)表示x

应用:求式子(a/b)%m的时候,由于b过大会出现爆精度的现象,有时为了精度也会用b的逆元去求式子。

b的逆元可以看作b在这个式子里的又一个倒数,b的逆元B会满足原式=(a×B)%m,但b并不是数学意义上的b的倒数,b的倒数往往是一个小数,而b的逆元不会这样。但是在这里b的逆元又满足这个式子。

费马小定理:若p是质数且gcd(a,p)=1,则a^(p-1)≡1 (mod p)

显然我们有a*a^(p-2)≡1 (mod p),即inv(a)=a^(p-2),用快速幂计算inv(a),复杂度log2(a),当模数p是质数时,用费马求解

·欧拉定理:若gcd(a,p)=1,则a^(φ(p))≡1(mod p)

显然此时inv(a)=a^(φ(p)-1),使用欧拉函数+快速幂计算,复杂度同费马,但较费马而言,模数p可以不为质数,因此应用范围广一点

·扩展欧几里得:若gcd(a,b)=1,则ax+by=1

//欧几里德
ll extend_gcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    else {
        ll r = extend_gcd(b, a % b, y, x);
        y -= x * (a / b);
        return r;
    }
}
ll inv(ll a, ll n) {
    ll x, y;
    extend_gcd(a, n, x, y);
    x = (x % n + n) % n;
    return x;
}

51nod1256 乘法逆元

给出2个数M和N(M < N),且M与N互质,找出一个数K满足0 < K < N且K * M % N = 1,如果有多个满足条件的,输出最小的。

解:真——求乘法逆元。。代码如下

#include 
#include
#include
#include
long long m,x,y;
 
using namespace std;
 
void ggcd(int a,int b){
    if(b==0){
        x=1;
        y=0;
        return;
    }
    else{
 
        ggcd(b,a%b);
        long long temp=x;
        x=y;//相当于x1=y2
        y=temp-(a/b)*y;//相当于y1=x2-(a/b)*y2
 
    }
}
int main(){
    long long n,h;
    scanf("%lld %lld",&n,&m);
    ggcd(n,m);
    while(x<0){
        x=(x+m)%m;
    }
    printf("%lld\n",x);
    return 0;
}

2.     51nod1013 3的幂的和

求:3^0 + 3^1 +...+ 3^(N) mod 1000000007

解:Sn=a1*(1-q^(n+1))/(1-q);q=3,a1=1,化简(q^(n+1)-1)/2;即这个式子对1000000007去余。

先求出2对1000000007的逆元,然后快速幂求q^(n+1)(因为(q^(n+1)太大了,所以在求的过程中一直对1000000007取余,防止爆精度),再-1,乘以2的逆元,最后对1000000007取余;代码如下:

#include 
#include
#include
#include
 
using namespace std;
typedef long long ll;
const int mod=1000000007;
long long X,y;
long long gcd(long long a,long long b){//计算逆元
    int t,d;
    if(b==0){
        X=1;
        y=0;
return a;
    }
        d=gcd(b,a%b);
        t=X;
        X=y;//相当于x1=y2
        y=t-(a/b)*y;//相当于y1=x2-(a/b)*y2
return d;
}
ll ksm(long long x,long long a,long long p){//快速幂取余
    ll ans=1;
    x=x%p;
    while(a>0){
        if(a&1){
            ans=(ans*x)%p;
        }
        x=(x*x)%p;
        a>>=1;
 
    }
    return ans;
 
}
 
int main(){
    long long n;
    scanf("%lld",&n);
    gcd(2,mod);//2%m    原式化简得(q^(n+1)-1)/ 2%m, 所以求2对mod的逆元;
    if(X<0){//
        X+=mod;
    }
    n++;
    ll ans=(ksm(3,n,mod)-1)*X%mod;//所以原式就变成了(q^(n+1)-1)×x(逆元)%m;
    printf("%lld\n",ans);
    return 0;
}

算数基本定理

任何一个大于1的自然数N,如果N不为质数,那么N可以分解成有限个质数的乘积,并且在不计次序的情况下,这种分解方式是唯一的。

容斥定理

要计算几个集合并集的大小,我们要先将所有单个集合的大小计算出来,然后减去所有两个集合相交的部分,再加回所有三个集合相交的部分,再减去所有四个集合相交的部分,依此类推,一直计算到所有集合相交的部分。

 

 

你可能感兴趣的:(总结)