A/B Problem

时间限制:1000 ms  |  内存限制:65535 KB

难度:3

输入

数据的第一行是一个T,表示有T组数据.
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9).

输出

对应每组数据输出(A / B) % 9973.

样例输入

2
1000 53
87 123456789

样例输出

7922
6060

描述

已知:

    1. n = (A % 9973);

    2. gcd(B, 9973) = 1;

计算:

    (A / B) % 9973

这题是裸逆元题,将B的逆元B’求出来即可.   BB'=1%9973=>(BB')%9973=1(1的前提条件)    (A/B)%9973=(A/B)*1%9973=>(A/B)*(BB')%9973%9973=>(AB')%9973%9973(两个模可去掉一个)=>(n*B')%9973就是答案了

逆元的定义:假设x是a的逆元,那么 a * x = 1(mod p)(这里p=9973,以下都是)

求逆元以下有两种方法,一个是费马小定理求逆元,一个是扩展欧几里得求逆元

注意的是 ( a/b )%p = (a%p  /  b%p)  %  p 这个公式是不成立的;;;;

先说费马小定理 

公式:a^(p-1)=1%p(与a * x = 1(mod p) 是不是很像);  化简为 a*a^(p-2)=1%p;a^ (p-2)就是a的逆元,所以上题调用幂pow(B,9973-2)就是B'了;(也可快速幂)

后说扩展欧几里得 

大概就是Ax+By=1;  逆元的定义  a * x = 1(mod p) 可化简为 a*x=p*y+1=>a*x-p*y=1 与欧几里得式子很像

费马小定理 (我这里是快速幂模板,从杜神代码那复制过来的)

#include<bits/stdc++.h>
#define in(a) scanf("%d",&a)
#define  ind(a) scanf("%lld",&a)
using namespace std;
typedef long long ll;
const int mod=9973;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll inv(ll a)
{
	return powmod(a,mod-2);
}
int main()
{
	int t;
	in(t);
	while(t--)
	{
		ll n,b;
		ind(n);ind(b);
		ll sum=inv(b);
		printf("%lld\n",(n*sum)%mod);
	}
}

欧几里得 

#include <iostream>
#include<cstdio>
using namespace std;
const int MOD = 9973;
/*
 *  扩展欧几里得法(求ax + by = gcd)
 */
//  返回d = gcd(a, b);和对应于等式ax + by = d中的x、y
long long extendGcd(long long a, long long b, long long &x, long long &y)
{
    if (a == 0 && b == 0)
    {
        return -1;  //  无最大公约数
    }
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extendGcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
//  求逆元 ax = 1(mod n)
long long modReverse(long long a, long long n)
{
    long long x, y;
    long long d = extendGcd(a, n, x, y);
    if (d == 1)
    {
        return (x % n + n) % n;
    }
    else
    {
        return -1;  //  无逆元
    }
}
int main(int argc, const char * argv[])
{
    int T;
    cin >> T;
    long long n, B;
    while (T--)
    {
        cin >> n >> B;
        long long b = modReverse(B, MOD);
        //printf("逆元:%lld\n",b);
        cout << (n * b) % MOD << '\n';
    }
    return 0;
}