同余定理+逆元 HPU17级暑期集训

a题是比较经典的扩展欧几里得习题,单独放在一篇博客里讲解。

B - A/B

要求(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

思路:设A=B*X。n=A-(A/mod)*mod,所以n=B*X-(A/mod)*mod。设(A/mod)=Y。所以原式等于:n=B*X-Y*mod。因为gcd(B,mod)=1,所以B*x-mod*y=1,方程两边同时乘于n,得到B*n*x-mod*y*n=n.所以X=n*x,其中X为B关于mod的逆元。然后就用扩展欧几里得解就可以了。

#include<algorithm>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int mod=9973;
ll x,y;
void exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1;
        y=0;
        return ;
    }
    exgcd(b,a%b,x,y);
    ll z=x;x=y;y=z-y*(a/b);
    //return d;
}
int main(){
    int t;
    scanf("%d",&t);
    ll n,b,x,y,ans;
    while(t--){
        scanf("%lld%lld",&n,&b);
        exgcd(b,mod,x,y);
        x=x*n;
        ll ans=(x%mod+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

C - 乘法逆元

 

给出2个数M和N(M < N),且M与N互质,找出一个数K满足0 < K < N且K * M % N = 1,如果有多个满足条件的,输出最小的。

Input

输入2个数M, N中间用空格分隔(1 <= M < N <= 10^9)

Output

输出一个数K,满足0 < K < N且K * M % N = 1,如果有多个满足条件的,输出最小的。

Sample Input

2 3

扩展欧几里得打表就可以了。注意如果k<0,要处理一下。

#include<algorithm>
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=1000005;
typedef long long ll;
void exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1;
        y=0;
        return ;
    }
    exgcd(b,a%b,x,y);
    ll z=x;x=y;y=z-y*(a/b);
    //return d;
}
int main(){
    ll m,n;
    ll x,y;
    while(~scanf("%lld%lld",&m,&n)){
        exgcd(m,n,x,y);
        int k=(x%n+n)%n;
        printf("%lld\n",k);
    }
    return 0;
}

Sample Output

2

D - 3的幂的和

求:3^0 + 3^1 +...+ 3^(N) mod 1000000007

Input

输入一个数N(0 <= N <= 10^9)

Output

输出:计算结果

Sample Input

3

Sample Output

40

题目大致思路:用等比数列前n项和公式可得((3^n+1-1)/2)mod,然后在由费马小定理求2关于mod的逆元。

#include<algorithm>
#include<cstdio>
#include<iostream>
#define mod 1000000007
using namespace std;
typedef long long ll;
ll poww(ll x,ll n){
    ll res=1;
    while(n>0){
        if(n&1) res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}
int main(){
    int n;
    while(~scanf("%d",&n)){
        ll x=(poww(3,n+1)-1)%mod;
        ll y=(poww(2,mod-2)%mod);//费马小定理计算2的乘法逆元
        ll ans=(x*y)%mod;
        printf("%lld\n",ans);
    }
}

E - Integer Divisibility

 

If an integer is not divisible by 2 or 5, some multiple of that number in decimal notation is a sequence of only a digit. Now you are given the number and the only allowable digit, you should report the number of digits of such multiple.

For example you have to find a multiple of 3 which contains only 1's. Then the result is 3 because is 111 (3-digit) divisible by 3. Similarly if you are finding some multiple of 7 which contains only 3's then, the result is 6, because 333333 is divisible by 7.

Input

Input starts with an integer T (≤ 300), denoting the number of test cases.

Each case will contain two integers n (0 < n ≤ 106 and n will not be divisible by 2 or 5) and the allowable digit (1 ≤ digit ≤ 9).

Output

For each case, print the case number and the number of digits of such multiple. If several solutions are there; report the minimum one.

Sample Input

3

3 1

7 3

9901 1

Sample Output

Case 1: 3

Case 2: 6

Case 3: 12

题目思路:大数取模,直接上板子就可以了,注意开到long long。

#include<algorithm>
#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
int main(){
    int t;
    scanf("%d",&t);
    long long kase=0,a,b;
    while(t--){
        scanf("%lld%lld",&a,&b);
        long long ans=b,cnt=1;
        while(ans%a!=0){
            ans=(ans*10+b)%a;
            cnt++;
        }
        printf("Case %lld: %lld\n",++kase,cnt);
    }
    return 0;
}

F - Large Division

 

Given two integers, a and b, you should check whether a is divisible by b or not. We know that an integer a is divisible by an integer b if and only if there exists an integer c such that a = b * c.

Input

Input starts with an integer T (≤ 525), denoting the number of test cases.

Each case starts with a line containing two integers a (-10200 ≤ a ≤ 10200) and b (|b| > 0, b fits into a 32 bit signed integer). Numbers will not contain leading zeroes.

Output

For each case, print the case number first. Then print 'divisible' if a is divisible by b. Otherwise print 'not divisible'.

Sample Input

6

101 101

0 67

-101 101

7678123668327637674887634 101

11010000000000000000 256

-202202202202000202202202 -101

Sample Output

Case 1: divisible

Case 2: divisible

Case 3: divisible

Case 4: not divisible

Case 5: divisible

Case 6: divisible

题目思路:在为负数的时候特判一下,然后直接上板子。

#include<algorithm>
#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
string a;
long long b;
int main(){
    int t;
    scanf("%d",&t);
    int kase=0;
    while(t--){
        cin>>a>>b;
        long long len=a.length();
        long long ans=0;
        long long i=0;
        if(a[0]=='-') i++;
        for(;i<len;i++){
            ans=(ans*10+a[i]-'0')%b;
        }
        if(ans==0) printf("Case %d: divisible\n",++kase);
        else printf("Case %d: not divisible\n",++kase);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值