HDU1792 A New Change Problem 推理+证明详解(关于数论中的互质数的最大不能组合数 )

Description:

Now given two kinds of coins A A A and B B B,which satisfy that G C D ( A , B ) = 1 GCD(A,B)=1 GCD(A,B)=1.Here you can assume that there are enough coins for both kinds.Please calculate the maximal value that you cannot pay and the total number that you cannot pay.

Input

The input will consist of a series of pairs of integers A A A and B B B, separated by a space, one pair of integers per line.

Output

For each pair of input integers A A A and B B B you should output the the maximal value that you cannot pay and the total number that you cannot pay, and with one line of output for each line
in input.

Sample Input

2 3
3 4

Sample Output

1 1
5 3

题意: 给定 A A A B B B A A A B B B互质,求最大不能组合数,和不能组合数的个数。

基础知识:

G c d ( A , B ) = 1 Gcd(A, B) = 1 Gcd(A,B)=1 L c m ( A , B ) = A B Lcm(A, B) = AB Lcm(A,B)=AB

剩余类,把所有整数划分成 m m m 个等价类,每个等价类由相互同余的整数组成。

任何数分成 m m m个剩余类,分别为 m k , m k + 1 , m k + 2 , … … , m k + ( m − 1 ) m_{k},m_{k+1},m_{k+2},……,m_{k+(m-1)} mkmk+1mk+2mk+(m1)

分别记为 0 ( m o d m ) , 1 ( m o d m ) … … {0(mod m)},{1(mod m)}…… 0(modm)1(modm)

n n n的倍数肯定分布在这 m m m个剩余类中

因为 G c d ( m , n ) = 1 Gcd(m,n)=1 Gcd(mn)=1,所以每个剩余类中都有一些数是 n n n的倍数,并且是平均分配它的旁证

k m i n = m i n { k ∣ n k ∈ i ( m o d m ) } , i ∈ [ 0 , m ] k_{min} = min\{ k | nk ∈ {i (mod m)} \}, i ∈ [0, m] kmin=min{knki(modm)},i[0,m]

n k m i n nk_{min} nkmin i ( m o d m ) {i (mod m)} i(modm) n n n 的最小倍数。特别的, n m ∈ 0 ( m o d m ) nm ∈ {0 (mod m)} nm0(modm)

n k m i n nk_{min} nkmin 是个标志,它表明 { i ( m o d m ) } 中 n k m i n \{i (mod m)\}中nk_{min} {i(modm)}nkmin 后面所有数,即 n k m i n + j m nk_{min} + j_{m} nkmin+jm 必定都能被组合出来

那也说明最大不能组合数必定小于 n k m i n nk_{min} nkmin

我们开始寻找 m a x { n k m i n } max\{ nk_{min} \} max{nkmin}

L c m ( m , n ) = m n Lcm(m, n) = mn Lcm(m,n)=mn,所以很明显 ( m − 1 ) n (m-1)n (m1)n 是最大的

因为 ( m − 1 ) n (m-1)n (m1)n n k m i n nk_{min} nkmin 中的最大值,所以在剩下的 m − 1 m-1 m1 个剩余类中,必定有比它小并且能被 m m m n n n 组合,这些数就是 ( m − 1 ) n − 1 (m-1)n -1 (m1)n1 ( m − 1 ) n − 2 , … … , ( m − 1 ) n − ( m − 1 ) (m-1)n -2,……,(m-1)n -(m-1) (m1)n2(m1)n(m1)

所以最大不能被组合数就是 ( m − 1 ) n − m (m-1)n -m (m1)nm

如果 m m m n n n 不互素,那 { 1 ( m o d m ) } \{1 (mod m)\} {1(modm)} 不能被 m m m 组合,同样也不能被 n n n m m m 组合

我们能求出各个剩余类的 n k m i n nk_{min} nkmin 之后,不能组合数的个数就是每个剩余类中小于各自 n k m i n nk_{min} nkmin 的数的个数总和。

观察如下:

M = 5 , N = 3 M = 5,N = 3 M=5N=3

0 ( m o d 5 ) : 0 , 5 , 10 , 15 … … {0(mod 5)}:0,5,10,15…… 0(mod5)051015

1 ( m o d 5 ) : {1(mod 5)}: 1(mod5)1 6 , 11 , 16 … … 6,11,16…… 61116

2 ( m o d 5 ) : {2(mod 5)}: 2(mod5)2,7 12 , 17 … … 12,17…… 1217

3 ( m o d 5 ) : 3 , 8 , 13 , 18 … … {3(mod 5)}:3,8,13,18…… 3(mod5)381318

4 ( m o d 5 ) : {4(mod 5)}: 4(mod5)4 9 , 14 , 19 … … 9,14,19…… 91419

红色的就是不能组合数,可以看出在剩余类中它的数目有规律

T o t a l = [ 0 + 1 + 2 ] + [ 0 + 1 ] Total = [0+1+2] + [0+1] Total=[0+1+2]+[0+1]

因为 m m m n n n 互质,必有一个不完全周期

整理以后,可得公式 T o t a l = ( n − 1 ) ∗ ( m − 1 ) / 2 Total = (n-1)*(m-1)/2 Total=(n1)(m1)/2

AC代码:

#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stack>
#include <queue>
using namespace std;
#define sd(n) scanf("%d", &n)
#define sdd(n, m) scanf("%d%d", &n, &m)
#define sddd(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define pd(n) printf("%d\n", n)
#define pc(n) printf("%c", n)
#define pdd(n, m) printf("%d %d", n, m)
#define pld(n) printf("%lld\n", n)
#define pldd(n, m) printf("%lld %lld\n", n, m)
#define sld(n) scanf("%lld", &n)
#define sldd(n, m) scanf("%lld%lld", &n, &m)
#define slddd(n, m, k) scanf("%lld%lld%lld", &n, &m, &k)
#define sf(n) scanf("%lf", &n)
#define sc(n) scanf("%c", &n)
#define sff(n, m) scanf("%lf%lf", &n, &m)
#define sfff(n, m, k) scanf("%lf%lf%lf", &n, &m, &k)
#define ss(str) scanf("%s", str)
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define mem(a, n) memset(a, n, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define fi first
#define se second
#define mod(x) ((x) % MOD)
#define gcd(a, b) __gcd(a, b)
#define lowbit(x) (x & -x)
typedef pair<int, int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
inline int read()
{
    int ret = 0, sgn = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            sgn = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        ret = ret * 10 + ch - '0';
        ch = getchar();
    }
    return ret * sgn;
}
inline void Out(int a) //Êä³öÍâ¹Ò
{
    if (a > 9)
        Out(a / 10);
    putchar(a % 10 + '0');
}

ll gcd(ll a, ll b)
{
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b)
{
    return a * b / gcd(a, b);
}
///快速幂m^k%mod
ll qpow(int m, int k, int mod)
{
    ll res = 1, t = m;
    while (k)
    {
        if (k & 1)
            res = res * t % mod;
        t = t * t % mod;
        k >>= 1;
    }
    return res;
}

// 快速幂求逆元
int Fermat(int a, int p) //费马求a关于b的逆元
{
    return qpow(a, p - 2, p);
}

///扩展欧几里得
ll exgcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll ans = exgcd(b, a % b, x, y);
    ll temp = x;
    x = y;
    y = temp - a / b * y;
    return ans;
}

///使用ecgcd求a的逆元x
ll mod_reverse(ll a, ll p)
{
    ll d, x, y;
    d = exgcd(a, p, x, y);
    if (d == 1)
        return (x % p + p) % p;
    else
        return -1;
}

///中国剩余定理模板

ll china(ll a[], ll b[], ll n)
{
    ll a1 = a[1], b1 = b[1];
    bool flag = 1;
    for (int i = 2; i <= n; i++)
    {
        ll A = a1, B = a[i], C = b[i] - b1;
        ll x, y;
        ll gcd = exgcd(A, B, x, y);
        if (C % gcd)
        {
            flag = 0;
            break;
        }
        x = ((x * C / gcd) % (B / gcd) + (B / gcd)) % (B / gcd);
        b1 = a1 * x + b1;
        a1 = a1 / gcd * a[i];
    }
    if (b1)
        return b1;
    else
        return a1;
}

int t;
ll a, b, n, m, k, ans;
int main()
{
    while (~sldd(n, m))
    {
        if (n < m)
        {
            a = n;
            n = m;
            m = a;
        }
        pldd((m - 1) * n - m, (n - 1) * (m - 1) / 2);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值