《数论练习》

P1516 青蛙的约会(洛谷)

题意:在一个循环坐标轴上,有两个初始坐标为x,y的点,每个人一次跳m,n步,求解是否可以相遇,如果可以求出最小步数。

假设跳了k步后两点相遇。则有

x+k*m - (y+k*n) = T * L(T为常数,即表示为L的常数倍,因为是循环坐标轴)

转化为 TL+(n-m)*k = x-y;

设 a = L,b = n-m,x = t,y = k,c = x-y;

那么式子转化为  ax+by = c;

显然是扩展欧几里得求解。

扩展欧几里得求得 ax0+by0 = gcd(a,b)-+
两边同时乘以c / gcd(a,b) (一定是整除,因为c是gcd(a,b)的倍数)
a*xo*c / gcd(a,b) + b*yo*c / gcd(a,b).
此时
x = xo*c / gcd(a,b);
y = yo*c / gcd(a,b)
x,y即为ax + by = c的一组特解。
关于求解最小正整数解的求法。
x = (x % (b/gcd(a,b)+gcd(a,b) ) % gcd(a,b)
y = (y % (a/gcd(a,b)+gcd(a,b) ) % gcd(a,b)
由定式推得(证明略)
需要注意的是,gcd只对非负整数有效。

b可能是负数,此时需要对等式两边取反,但是a不用取反,因为可以将x看成-T来实现取反效果。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<LL,int> pii;
const int N = 1e3+5;
const int M = 1e6+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define INM INT_MIN
#define dbg(ax) cout << "now this num is " << ax << endl;
inline LL read()
{
    LL x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
LL xx,yy,n,m,L;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(b == 0)
    {
        x = 1,y = 0;
        return a;
    }
    LL t = exgcd(b,a%b,y,x);
    y -= a/b*x;
    return t;
}
int main() 
{
    xx = read(),yy = read(),m = read(),n = read(),L = read();
    LL a = L,b = n-m,c = xx-yy,x,y;
    if(b < 0) b = -b,c = -c;
    LL gcd = exgcd(a,b,x,y);
    if(c%gcd != 0) printf("Impossible\n");
    else
    {
        LL ma = c/gcd*y;
        LL ans = (ma % (a/gcd) + (a/gcd))%(a/gcd);
        printf("%lld\n",ans);
    }
   // system("pause");
    return 0;
}
View Code

The Balance(POJ 2142)

题意:给定两个种类砝码,和一个要称量的物体。计算是否能够通过天平测量出这个物品,如果能,求最少需要的砝码总和。

设a种砝码x个,b种砝码y个。称量的物体种类为c。

即满足a*x + b*y = c.

注意的是砝码可以放左和右。那么这里定义放左为正,右为负,所以x,y可能为负。

这里求的即为abs(x) + abs(y)的最小值。

可以证明,肯定是满足一边为最小正整数个时,总和最小。

那么扩展欧几里得可以计算出x为最小正整数时,和y为最小正整数时的情况,求最小的情况即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<LL,int> pii;
const int N = 1e5+5;
const int M = 1e6+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define INM INT_MIN
#define dbg(ax) cout << "now this num is " << ax << endl;
inline LL read()
{
    LL x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
int exgcd(int a,int b,int &x,int &y)
{
    if(b == 0)
    {
        x = 1,y = 0;
        return a;
    }
    int t = exgcd(b,a%b,y,x);
    y -= a/b*x;
    return t;
}
int main()
{
    int a,b,d,x,y;
    while((a = read(),b = read(),d = read()),a || b || d)
    {
        int gcd = exgcd(a,b,x,y);
        if(d % gcd != 0) printf("no solution\n");
        else
        {
            int t1 = x*d/gcd,t2 = y*d/gcd;
            int ma1 = (t1%(b/gcd)+(b/gcd))%(b/gcd);//最小正整数x
            int ma2 = (t2%(a/gcd)+(a/gcd))%(a/gcd);//最小正整数y
            int ma3 = abs((d-a*ma1)/b);//注意取绝对值,因为可能是放在不同边
            int ma4 = abs((d-b*ma2)/a);//同理
            if(ma1+ma3 < ma2+ma4) printf("%d %d\n",ma1,ma3);
            else printf("%d %d\n",ma4,ma2);
        }
    }
    system("pause");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zwjzwj/p/13424464.html