CodeVS3990:中國餘數定理 2 (CRT)

題目傳送門:http://codevs.cn/problem/3990/


題目分析:這是一道CRT入門題。

關於CRT入門我是看MashiroSky大神的blog,個人認爲寫得很好。

然後以下的東西是給自己複習用的,簡記一下,大概寫得很爛QAQ:

現在要求k 個形如xci(modmi) 的同餘方程組的最小非負整數解x ,其中mi 兩兩互質。記M=i=1kmi ,那麼很明顯x[0,M) 。現在考慮如何讓x 滿足第一個方程的條件而不影響其它方程。我們可以算出一個其它所有mi 的lcm的倍數,即Mm1 的倍數,使得它模m1 剛好等於c1 。也就是要求:

kMm1c1(modm1)

所以只要算出Mm1modm1 下的逆元,再乘以c1 即爲k 。用k 乘以Mm1 即爲要求的lcm的倍數。

然後對於m2 ~mk 也這樣操作,最後將這些數加起來模M ,即爲x 。考慮最終的x 模每個mi 的結果,就會發現這樣操作正確性顯然。於是得出式子:

xi=1kciMmiInv(Mmi,mi)(modM)

其中Inv(x,y) 表示x關於y的逆元。

這個式子其實是有很多侷限性的,比如M 不能太大。在本題中由於M 達到1014 ,如果寫費馬小定理求逆元要用快速乘。但當某些算法的模數很難處理的時候,可以用CRT將其分解,然後合併。另外,由於符合條件的x[0,M) 中僅有唯一取值,還可以將原先難以處理的模數用其它幾個方便處理的互質的模數代換,然後用CRT求出其真實值。比如經典的任意模數NTT,只要選取的模數使M>NP2 ,即可唯一確定多項式每一位的值。其中M 是選取模數之積,N 是多項式的次數界,P 是原模數。因爲卷積後多項式每一位的值不會超過NP2


CODE:

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;

const int maxn=15;
typedef long long LL;

LL m[maxn];
LL c[maxn];
LL M;

LL X,Y;
LL a,b;
int n;

void Exgcd(LL u,LL v)
{
    if (!v) X=1,Y=0;
    else
    {
        Exgcd(v,u%v);
        LL p=X;
        LL q=Y;
        X=q; //!!!
        Y=p-u/v*q; //!!!
    }
}

int main()
{
    freopen("3990.in","r",stdin);
    freopen("3990.out","w",stdout);

    scanf("%d%I64d%I64d",&n,&a,&b);
    M=1;
    for (int i=1; i<=n; i++) scanf("%I64d%I64d",&m[i],&c[i]),M*=m[i];
    LL k=0;
    for (int i=1; i<=n; i++)
    {
        Exgcd(m[i],M/m[i]%m[i]);
        while (Y<0) Y+=m[i];
        k=(k+ M/m[i]*c[i]%M*Y%M )%M;
    }

    a-=k;
    b-=k;
    LL num=(b+M)/M-(a-1+M)/M; //!!!
    if (!num) printf("0\n0\n");
    else
    {
        a=(a+M-1)/M*M+k;
        printf("%I64d\n%I64d\n",num,a);
    }

    return 0;
}
發佈了160 篇原創文章 · 獲贊 76 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章