2018 Arab Collegiate Programming Contest (ACPC 2018) H - Hawawshi Decryption 数学 + BSGS
对于一个给定的生成数列
R[ 0 ] 已知, (R[ i - 1 ] * a + b) % p = R[ i ] (p 是 质数), 求最小的 x 使得 R[ x ] = t
我们假设存在这样一个数列 S[ i ] = R[ i ] - v, 并且S[ i - 1] * a = S[ i ], 那么将S[ i ] = R[ i ] - v带入可得
v = b / (1-a) 那么我们能得到 R[ i ] = (R[ 0 ] - v) * a ^ n + v, 然后就是解一个高次剩余方程,
注意 a == 1 和 R[ 0 ] == v的情况需要特殊考虑。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ull unsigned long long using namespace std; const int N = 1e4 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); int n, x, L, R, a, b, p, T, y; struct hashTable { int head[N+5], tot; struct node { int val, id, nx; } a[N+5]; void init() { memset(head, -1, sizeof(head)); tot = 0; } void Insert(int val, int id) { int p = val % N; a[tot].val = val; a[tot].id = id; a[tot].nx = head[p]; head[p] = tot++; } int Find(int val) { int p = val % N; for(int i = head[p]; ~i; i = a[i].nx) if(a[i].val == val) return a[i].id; return -1; } } mp; int fastPow(int a, int b) { int ans = 1; while(b) { if(b & 1) ans = 1ll*ans*a%p; a = 1ll*a*a%p; b >>= 1; } return ans; } int BSGS(int a,int b,int p) { if(b == 1) return 0; if(a == b) return 1; if(!b) return !a ? 1 : -1; mp.init(); int m = ceil(sqrt(p)), x = 1, y, z; for(int i = 1; i <= m; i++) { x = 1ll * x * a % p; if(mp.Find(x) == -1) mp.Insert(x, i); } x = 1, y = fastPow(a, p-m-1); for(int i = 0; i < m; ++i) { z = mp.Find(1ll*x*b%p); if(~z) return i * m + z; x = 1ll * x * y % p; } return -1; } int main() { // freopen("hawawshi.in", "r", stdin); scanf("%d", &T); while(T--) { scanf("%d%d%d%d%d%d%d", &n, &x, &L, &R, &a, &b, &p); int q = 0, r = R-L+1; if(a == 1) { for(int R0 = L; R0 <= R; R0++) { int pos = 1ll*(x-R0+p)%p*fastPow(b, p-2)%p; if(pos < n) q++; } } else { int v = 1ll * b * fastPow(1-a+p, p-2) % p; for(int R0 = L; R0 <= R; R0++) { if(R0 == v) { if(R0 == x) q++; } else { int pos = BSGS(a, 1ll*(x-v+p)%p*fastPow((R0-v+p)%p, p-2)%p, p); if(~pos && pos < n) q++; } } } int gcd = __gcd(q, r); printf("%d/%d\n", q/gcd, r/gcd); } return 0; } /* */