背景
对于关于x的类型同余方程,求其最小解
可以判断方程有无解
首先若p为素数,由完全剩余系可知有解,p不为素数:若则
,否则且对于
,要若
才可能有解。
若方程有解,由,
为阶.可知将
从
进行p次枚举一定可以得到解
BSGS就是将通过将枚举次数上界变为
的算法
BSGS算法=>且
在上述的讲解中我们确定了枚举上界次数,那么考虑如何将次数给降下来
对x做带余除法,我们考虑对
进行枚举
对于每个若我们能快速判断
是否成立即可,变下形,即
即每个值,判断是否有对应的
值即可
可知若找到,则第一个值即为最小值(),若有多个
值,为了使
更小应取最大的
对于值用
表进行记录即可(若有相同的保证较大,用后者进行覆盖)
时间方面:处理为
,
的枚举为
,故取
合适
给定整数和质数
,求最小的正整数
,使得
(N个1)
将看作等比数列
的和,变形即为
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
using namespace std;
using LL = long long;
const int MAXN = 1e6 + 5;
LL K, M, block, XN;
unordered_map<LL, int> MP;
LL qpow(LL, LL);
LL multi(LL a, LL b);
int main(){
cin >> K >> M;
LL tmp = 1; XN = 1;
//while(tmp % M != K) tmp = (10 * tmp + 1) % M, XN++;
//cout << XN << endl;
K = (9 * K + 1LL) % M, block = (LL)ceil(sqrt(M));
LL inv_K = qpow(K, M - 2);
LL i, j;
tmp = K, XN = 2e15;
for(i = 0; i < block; i++){
MP[tmp] = i;
tmp = tmp * 10 % M;
}
for(i = 1; i <= block + 1; i++){
tmp = qpow(10, i * block);
if(MP.find(tmp) != MP.end()) XN = min(XN, i * block - MP[tmp]);
}
cout << XN << endl;
return 0;
}
LL multi(LL a, LL b){
return ((a * b - (LL)((LL)((long double)a / M * b + 1e-3) * M)) % M + M) % M;
}
LL qpow(LL x, LL n){
LL res = 1;
while(n){
if(n & 1) res = multi(res, x);
x = multi(x, x);
n >>= 1;
}
return res;
}
//2
//1000000007
//696967963
EXBGSG算法:但
通过上述说明可以知道,我们可以在时间对问题求解,但实际情况可能
,但
我们就需要对方程进行一定的预处理:
设,可以知若
要么
(直接可以得解)要么方程无解,若
,由同余运算可知
,可以看到,相当于方程变为
一直进行该过程直到,方程变为
进行枚举即可
过程中需要特判的情况(后面枚举会有遗漏)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
using namespace std;
using LL = long long;
LL A, B, P;
LL gcd(LL, LL);
LL qpow(LL, LL, LL);
LL exBSGS(LL, LL, LL);
LL getint();
int main(){
ios::sync_with_stdio(false);
int i;
while(cin >> A >> P >> B){
if(A != 0 && B != 0 && P != 0){
LL ans = exBSGS(A, B, P);
if(ans == -1) cout << "No Solution" << endl;
else cout << ans << endl;
}else break;
}
return 0;
}
unordered_map<LL, LL> MP;
LL exBSGS(LL a, LL b, LL p){
a %= p, b %= p;
if(!a) return (b) ? -1 : 0;
if(b == 1) return 0;
LL i, j, tmp, d = gcd(a, p), k = 0, t = 1;
while(d != 1){
if(b % d) return -1;
k++;
b /= d, p /= d, t = (t * (a / d)) % p;
d = gcd(a, p);
if(t == b) return k;
}
MP.clear();
LL m = ceil(sqrt(p));
for(j = 0, tmp = b; j < m; j++)
MP[tmp] = j, tmp = tmp * a % p;
j = qpow(a, m, p);
for(i = 1, tmp = t; i <= m + 1; i++){
tmp = tmp * j % p;
if(MP[tmp]) return i * m - MP[tmp] + k;
}
return -1;
}
inline LL qpow(LL x, LL n, LL mod){
LL res = 1;
while(n){
if(n & 1) res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
inline LL gcd(LL x, LL y){
return (!y) ? x : gcd(y, x % y);
}