给定正整数A, B, K, 求
背景知识
中国剩余定理
设
原根
拉格朗日定理 设
有限群
下面考虑模
若
离散对数
当
设
使用meet-in-middle的策略, 枚举
同余式的一个性质
若
模线性方程
设
两种做法公用的部分
首先将
先看一种特殊情形:
求这个方程在
取
的一个原根 , 设 ( 是唯一的), 则上述方程转化为 , 对大步小步算法稍加改写, 以求得解的数目. 由于这里规定了 的范围, 所以模 的最后一个周期直接枚举.如果
和 不互质, 则无解. 还是取原根 , 设 , 方程转化为 . 用大步小步算法求出 . 在 上的解与原方程的解一一对应. 根据模线性方程相关知识, 该方程有解当且仅当 , 如果有解, 解的数目是 .
做法一
来自我自己.
若
若
问题顺利解决. 写代码的时候, 我把
做法二
参考 - Po姐的题解 - 【BZOJ 2219】【超详细题解】数论之神 Regina8023.
思路大体相同, 中国剩余定理.
做法一讨论了
若
若
和做法一中的递归类似, 这个方程解的个数要乘上
感想
这道题的综合性比较强, 涉及了不少初等数论的知识. 细心分类讨论, 关注定义域的变化.
#include <bits/stdc++.h>
#define Rep(i, a, b) for (int i = (a), i##_ = (b); i < i##_; ++i)
#define For(i, a, b) for (int i = (a), i##_ = (b); i <= i##_; ++i)
#define Down(i, a, b) for (int i = (a), i##_ = (b); i >= i##_; --i)
using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
typedef vector<ii> Vec;
typedef Vec::iterator iter;
struct Hash {
const static int M = 38321;
vector<ii> h[M];
int cnt, used[M];
void insert(int v)
{
int k = v % M;
if (h[k].empty()) used[cnt++] = k;
for (iter x = h[k].begin(); x != h[k].end(); ++x)
if (x->first == v) {
++x->second;
return;
}
h[k].push_back(ii(v, 1));
}
int operator[](int v)
{
int k = v % M;
for (iter x = h[k].begin(); x != h[k].end(); ++x)
if (x->first == v)
return x->second;
return 0;
}
void clear()
{
while (cnt) h[used[--cnt]].clear();
}
} H;
void decompose(int n, Vec& v)
{
for (int d = 2; d*d <= n; ++d) {
if (n % d == 0) {
ii t(1, d);
do {
t.first *= d;
n /= d;
} while (n % d == 0);
v.push_back(t);
}
}
if (n > 1)
v.push_back(ii(n, n));
}
ll fp(ll x, ll n)
{
ll y = 1;
for (; n; n >>= 1, x *= x)
if (n & 1)
y *= x;
return y;
}
ll fpm(ll x, ll n, ll m)
{
ll y = 1;
for (; n; n >>= 1, (x *= x) %= m)
if (n & 1)
(y *= x) %= m;
return y;
}
int bsgs(ll a, ll y, ll n, ll r)
{
H.clear();
int m = round(sqrt(r)), cnt = 0;
ll t = y;
For (i, 1, m) // y*a^i, i=1,2,...,m
H.insert((t *= a) %= n);
ll d = fpm(a, m, n);
t = 1;
For (i, 1, r/m) // (a^m)^i, i=1,2,...,floor(r/m)
cnt += H[(t *= d) %= n];
Rep (i, r/m*m, r) // a^i, i=m*floor(r/m),...,r-1
cnt += t == y, (t *= a) %= n;
return cnt;
}
int primitive_root(int a, int p, int r)
{
Vec v;
decompose(r, v);
Rep (g, 2, a) if (g % p) {
bool ok = true;
for (iter x = v.begin(); x != v.end(); ++x)
if (fpm(g, r/x->second, a) == 1) {
ok = false;
break;
}
if (ok) return g;
}
assert(0);
return -1;
}
int solve(int a, int b, int m, int p, int k)
{
if (!b) return fp(p, k-(k+a-1)/a);
int phi = m/p*(p-1), g = primitive_root(m, p, phi), ans = bsgs(fpm(g, a%phi, m), b, m, phi);
if (a < k) {
int t = fp(p, a), m1 = m / t;
if (b % t == 0)
ans += t / p * solve(a, b/t%m1, m1, p, k-a);
}
return ans;
}
int main()
{
int T, K, A, B;
scanf("%d", &T);
while (T--) {
scanf("%d%d%d", &A, &B, &K);
Vec v;
decompose(2*K + 1, v);
int ans = 1;
for (iter x = v.begin(); x != v.end(); ++x) {
int m = x->first, p = x->second, k = 1;
for (int t = p; t < m; t *= p) ++k;
ans *= solve(A, B % m, m, p, k);
}
printf("%d\n", ans);
}
return 0;
}