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

Description:

Now given two kinds of coins A A and B B ,which satisfy that G C D ( 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 and B B , separated by a space, one pair of integers per line.

Output

For each pair of input integers A A and 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 B B A A B B 互质,求最大不能组合数,和不能组合数的个数。

基础知识:

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

剩余类,把所有整数划分成 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)}

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

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

因为 G c d ( m n ) = 1 Gcd(m,n)=1 ,所以每个剩余类中都有一些数是 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]

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

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

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

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

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

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

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

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

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

观察如下:

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

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

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

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

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

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

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

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

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

整理以后,可得公式 T o t a l = ( n 1 ) ( m 1 ) / 2 Total = (n-1)*(m-1)/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;
}

发布了611 篇原创文章 · 获赞 390 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/qq_43627087/article/details/103616280