Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 4283 | Accepted: 1970 |
Description
BL == N (mod P)
Input
Output
Sample Input
5 2 1 5 2 2 5 2 3 5 2 4 5 3 1 5 3 2 5 3 3 5 3 4 5 4 1 5 4 2 5 4 3 5 4 4 12345701 2 1111111 1111111121 65537 1111111111
Sample Output
0 1 3 2 0 3 1 2 0 no solution no solution 1 9584351 462803587
Hint
B(P-1) == 1 (mod P)
for any prime P and some other (fairly rare) numbers known as base-B pseudoprimes. A rarer subset of the base-B pseudoprimes, known as Carmichael numbers, are pseudoprimes for every base between 2 and P-1. A corollary to Fermat's theorem is that for any m
B(-m) == B(P-1-m) (mod P) .
題意:求L使B的L次冪與N對P同餘。
題目很短,一開始以爲是數學題,想着還要推公式,好麻煩。後來才發現有hint,但是並沒有什麼用,因爲按公式敲完一定會超時。學長說用BSGS做,就找了一下模板,半知半解吧,沒有完全搞懂,就當收集了一個新模板吧,感覺BSGS算法大多是都是解數學題,以後再做類似題的時候再做擴展。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define maxn 76567
using namespace std;
int head[maxn], nextt[maxn], e[maxn], cnt, hash[maxn];
int find(int x)
{
int k = x % maxn;
for(int i = head[k]; i != -1; i = nextt[i])
{
if(hash[i] == x)
return e[i];
}
return -1;
}
int BSGS(int b, int n, int p)
{
memset(head, -1, sizeof(head));
cnt = 1;
if(n == 1)
return 0;
int m = sqrt(p);
long long q = 1;
for(int i = 0; i < m; i++)
{
int k = ((q * n) % p) % maxn;
hash[cnt] = (q * n) % p;
e[cnt] = i;
nextt[cnt] = head[k];
head[k] = cnt;
cnt++;
q = q * b % p;
}
int j;
long long x = 1;
for(long long i = m; ; i += m)
{
if((j = find(x = x * q % p)) != -1)
return i - j;
if(i > p)
break;
}
return -1;
}
int main()
{
int p, n, b;
while(scanf("%d%d%d", &p, &b, &n) != EOF)
{
int ans = BSGS(b, n, p);
if(ans == -1)
printf("no solution\n");
else
printf("%d\n",ans);
}
}