HDUOJ1576.A/B(逆元 / 数论)

HDUOJ 1576.A/B

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10675 Accepted Submission(s): 8542

Problem Description
要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。

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

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

Sample Input
2
1000 53
87 123456789

Sample Output
7922
6060

Author
xhd

Source
HDU 2007-1 Programming Contest
这道题看上去很简单,其实还是蛮难的。很考验数学的能力,这里给出两种做法。

做法一:

要求的设为 x= A B \frac{A}{B} BAmod 9973,则可知 A B \frac{A}{B} BA=9973 * k 1 k_1 k1 + x。
又有A mod 9973=n。
则可以设A=9973 * k 1 k_1 k1 * B + x * B= k 2 k_2 k2 * 9973 + n。
可知 9973 * k 1 k_1 k1 * B + x * B - n= k 2 k_2 k2 * 9973。
两边同时 mod 9973 可知(x * B - n) mod 9973 =0;
不难看出B 和 n是已知的,x有0 <= x <= 9972,则可以枚举x的值以得出答案。
附上Ac代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,b;
        cin>>n>>b;
        for(int i=0;i<9973;i++)
        {
            if(((((b%9973)*i)%9973-n)%9973)==0)
            {
                cout<<i<<endl;
                break;
            }
        }
    }
    return 0;
}

做法二:

第二种方法则要引入逆元的思想。
因为要求的是 x = A B \frac{A}{B} BAmod 9973,可以写作x = (A * B − 1 {B}^{-1} B1) mod 9973。(其中 B − 1 {B}^{-1} B1是B关于模9973的乘法逆元)
把括号去掉:x = (A mod 9973 * B − 1 {B}^{-1} B1 mod 9973) mod 9973。
化简:x = (n * B − 1 {B}^{-1} B1 mod 9973)mod 9973。
已知gcd(B,9973)=1,又知道9973是一个质数,那么久可以直接使用费马小定理去求 B − 1 {B}^{-1} B1的值。
*费马小定理:假如p是质数,且gcd(a,p)=1,那么 a p − 1 {a}^{p-1} ap1≡1(mod p)。
B 9973 − 1 {B}^{9973-1} B99731≡1(mod 9973)。
可以写成B * B 9971 {B}^{9971} B9971≡1(mod 9973)。
又因为 B − 1 {B}^{-1} B1是B关于模9973的乘法逆元,则B * B − 1 {B}^{-1} B1≡1(mod 9973)。
可得 B − 1 {B}^{-1} B1= B 9971 {B}^{9971} B9971
带入前面的化简式中,可知:x = (n * B 9971 {B}^{9971} B9971 mod 9973)mod 9973。
B 9971 {B}^{9971} B9971 mod 9973可以使用快速幂算出,再带入式子,便可以直接算出结果x。
附上Ac代码:

#include <iostream>
#include <algorithm>
using namespace std;

int ksm(int a,int b,int mod)
{
    int r=1,c=a%mod;
    while(b)
    {
        if(b%2)
			r=(r*c)%mod;
		c=(c*c)%mod;
		b=b/2;
    }
    return r;
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,b;
        cin>>n>>b;
        cout<<(n*ksm(b,9971,9973))%9973<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值