cf/Codeforces ECR16-D - Two Arithmetic Progressions-中国剩余定理

来源:互联网 发布:java 数组去重效率 编辑:程序博客网 时间:2024/05/21 11:20

Problem ECR16-D - Two Arithmetic Progressions-

题目大意

 给两个等差数列 You are given two arithmetic progressions: a1k + b1 and a2l + b2. Find the number of integers x such that L ≤ x ≤ R andx = a1k' + b1 = a2l' + b2, for some integers k', l' ≥ 0.  

给一个L,R,问L到R里有多少个x满足  x = a1k' + b1 = a2l' + b2,

   数据范围:a1,a2,b1,b2,L,R <= 10^18。

解题分析

   其实题目的式子可以转化为两个模仿方程,也就是 x=b1(mod a1 )  ,x=b2(mod a2 )

由于a1,a2并不互质,不能直接用中国剩余定理,我们需要通过把式子都合并起来,再使用中国剩余定理

 如果两个式子不能合并,那么就是找不到x,输出0,否则就找一个比L小的 正解cur,然后看看cur到L-1里有多少个解,cur到R里有多少个解。


由于题目的直线斜率是正的,因此 x的最小取值为max(b1,b2),L取max(L,max(b1,b2))

 


参考程序


 

#include <iostream>#include <string.h>#include <stdio.h>using namespace std;typedef long long ll;const int N = 1005;ll a[N], m[N];ll gcd(ll a,ll b){    return b? gcd(b, a % b) : a;}void extend_Euclid(ll a, ll b, ll &x, ll &y){    if(b == 0)    {        x = 1;        y = 0;        return;    }    extend_Euclid(b, a % b, x, y);    ll tmp = x;    x = y;    y = tmp - (a / b) * y;}ll Inv(ll a, ll b){    ll d = gcd(a, b);    if(d != 1) return -1;    ll x, y;    extend_Euclid(a, b, x, y);    return (x % b + b) % b;}bool merge(ll a1, ll m1, ll a2, ll m2, ll &a3, ll &m3){    ll d = gcd(m1, m2);    ll c = a2 - a1;    if(c % d) return false;    c = (c % m2 + m2) % m2;    m1 /= d;    m2 /= d;    c /= d;    c *= Inv(m1, m2);    c %= m2;    c *= m1 * d;    c += a1;    m3 = m1 * m2 * d;    a3 = (c % m3 + m3) % m3;    return true;}ll cur,mm;ll CRT(ll a[], ll m[], int n){    ll a1 = a[1];    ll m1 = m[1];    for(int i=2; i<=n; i++)    {        ll a2 = a[i];        ll m2 = m[i];        ll m3, a3;        if(!merge(a1, m1, a2, m2, a3, m3))            return -1;        a1 = a3;        m1 = m3;    }    cur=a1,mm=m1;    return (a1 % m1 + m1) % m1;}int main(){    int n=2;    ll L,R;    for(int i=1; i<=n; i++)        scanf("%lld%lld",&m[i], &a[i]);    scanf("%lld%lld",&L,&R);    ll ans = CRT(a, m, n);    if (ans==-1)    {        printf("0\n");        return 0;    }    L=max(L,max(a[1],a[2]));        //***    //cal ans between [L-1,R]    ans=0;    if (cur>=L) cur-=((cur-L)/mm+1)*mm;  //find a cur that < L    if (L<=R)        ans= (R-cur)/mm-(L-1-cur)/mm;    printf("%lld\n",ans);    return 0;}

0 0