[数论]计算器

题目

解题思路

分三个部分,考验算法了。

1.

第一个操作很简单,就是一个快速幂,这里有人可能会问可不可以用降幂公式。所谓降幂公式,其实就这样。

?^?≡?^(?%?(?)+?(?) ) (??? ?), ?≥?(?)

我们看一下数据范围,发现m确实可能是非常大的,又是一个质数,因而varphi(m)的值就是m-1,细细看一下,发现可能得不偿失,还不如不用得了。因而直接用快速幂。

2.

第二个操作就是解一个二元一次不定方程,我们姑且用ax+by = c表示一下。算法用exgcd即可,以前有一道题目好像用exgcd就直接得到最小正整数解,这里我觉得是数据的问题,因而我们还应进行处理,按照叶学长的说法,用一些简单的四则运算就可以得到我们想要的特解。

在这里先表示通解。

这里的u为b/d,v即为-a/d,d=(a,b)。

方程无解的情况其实比较好判断,仅需判断c是否整除d即可。

3.

最近新学的一个算法BSGS,刚开始感觉难度很大,也不好打代码,现在倒是慢慢理解了。

这个算法求解a^{_{x}}equiv b(mod p)

条件要使得a,p互质,这里有问题了,数据只说p为素数却未说互质,因此我们要单独判断一下,如果a % p等于0了,当b等于1时有一个解0,否则无解。

我们令

m = left lceil p 
ight 
ceil,r = x % m

可以保证

x = k * m - r

于是

a^{^{k * m-r}}equiv b(mod p)

我们将k*m保留在左边,于是我们就可以处理出b * a的i(i<=r)的值保存在map中。因而再枚举左边,发现map中有即可。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
int n,k,y,z,p;
map<long long,long long>mp;
void exgcd(int a,int b,int &gcd,long long &x,long long &y){
    if (b == 0){
        gcd = a;
        x = 1,y = 0;
        return ;
    }
    exgcd(b,a % b,gcd,y,x);
    y -= (a / b) * x;
    return ;
}
long long qkpow(long long x,long long y,long long mod){
    long long ans = 1;
    while (y){
        if (y & 1)
            ans = ans * x % mod;
        x = x * x % mod;
        y /= 2;
    }
    return ans;
}
void solve1(int y,int z,int p){
    printf("%lld
",qkpow(y,z,p));
}
void solve2(int y,int z,int p){
    int gcd = 0;
    long long x0,y0;
    exgcd(y,p,gcd,x0,y0);
    if (z % gcd != 0){
        printf("Orz, I cannot find x!
");
        return ;
    }
    x0 = z / gcd * x0;
    long long t = abs(x0) / (p / gcd);
    if (x0 < 0){
        x0 += (p / gcd) * t;
        while (x0 < 0)
            x0 += (p / gcd);
    }
    else if (x0 > 0)
    {
        x0 -= (p / gcd) * t;
        while (x0 < 0)
            x0 += (p / gcd);
    }
    printf("%lld
",x0);
}
void solve3(int y,int z,int p){
	if (y % p == 0){
		if (z == 1){
			printf("0
");
			return ;
		}
		else {
			printf("Orz, I cannot find x!
");
			return ;
		}
	}
    long long m = ceil(sqrt(p));
    long long sum = 1;
    for (int i = 0;i <= m;i ++){
        mp[sum * z % p] = i;
        sum = sum * y % p;
    }
    long long s = qkpow(y,m,p);
    long long tmp = 1,ans = -1;
    for (int i = 1;i <= m;i ++){
        tmp = tmp * s % p;
        if (mp[tmp]){
            ans = m * i - mp[tmp];
            break;
        }
    }
    if (ans == -1)
        printf("Orz, I cannot find x!
");
    else 
        printf("%lld
",ans);
    mp.clear();
}
int main(){
    while (scanf ("%d%d",&n,&k) != EOF){
        for (int i = 1;i <= n;i ++){
            scanf("%d%d%d",&y,&z,&p);
            if (k == 1)
                solve1(y,z,p);
            if (k == 2)
                solve2(y,z,p);
            if (k == 3)
                solve3(y,z,p);
        }
    }
}
原文地址:https://www.cnblogs.com/lover-fucker/p/13566685.html