HDU 6956. Pass! 題解
阿新 • • 發佈:2021-07-21
HDU 6956. Pass!
題目連結:HDU 6956. Pass!
題意:
足球場上有\(n\)個球員傳球。開始時,球在第\(1\)個球員的腳下,然後每過一秒,有球的球員需要將球傳給任意其他的球員。設經過\(t\)秒後,球回到第\(1\)個球員的方法數模\(998244353\)的結果為\(x\),現已知\(x\),求最小的整數\(t\)。
輸入:
第\(1\)行,一個整數\(T(1\leq T\leq 100)\),代表測試樣例個數
對於每一個樣例:
只有\(1\)行,有\(2\)個整數\(n,x(2\leq n\leq 10^6,0\leq x<998244353)\)
輸出:
輸出最小的整數\(t\),若不存在,輸出\(-1\)
分析:
設經過\(t\)秒後,球回到第\(1\)個球員的方法數為\(a_t\),球沒有回到第\(1\)個球員的方法數為\(b_t\)。
-
考慮\(a_t\)和\(a_{t-1}\)與\(b_{t-1}\)的關係。
- 若\(t-1\)秒時球在第\(1\)個球員處,則第\(t\)秒不能夠傳給第\(1\)個球員,方法數為\(0\)。
- 若\(t-1\)秒時球不在第\(1\)個球員處,則第\(t\)秒只有一種方法傳給第\(1\)個球員,方法數為\(b_{t-1}\)。
所以存在遞推式
\[a_t=b_{t-1} \] -
考慮\(b_t\)和\(a_{t-1}\)與\(b_{t-1}\)的關係。
- 若\(t-1\)秒時球在第\(1\)個球員處,則第\(t\)秒可以傳給除了自己以外的\(n-1\)個球員,方法數為\((n-1)a_{t-1}\)。
- 若\(t-1\)秒時球不在第\(1\)個球員處,則第\(t\)秒可以傳給剩下除了自己和第\(1\)個球員以外的\(n-2\)個球員,方法數為\((n-2)b_{t-1}\)。
所以存在遞推式
\[b_t=(n-1)a_{t-1}+(n-2)b_{t-1} \]
聯立上面兩個遞推式,消去\(b\),可以得到
\[a_{t+1}=(n-1)a_{t-1}+(n-2)a_{t} \]該遞推式的特徵方程為
解得
\[r_1=-1,r_2=n-1 \]故通解為
\[a_t=C_1\cdot(-1)^t+C_2\cdot(n-1)^t \]又有\(a_1=0,a_2=n-1\),有
\[-C_1+(n-1)C_2=0 \\ C_1+(n-1)^2C_2=n-1 \]解得
\[C_1=1-\frac{1}{n},C_2=\frac{1}{n} \]所以最終通項公式為
\[a_t=(-1)^{t}+\frac{(-1)^{t+1}+(n-1)^t}{n} \]當\(t\)為奇數的時候
\[-1+\frac{1+(n-1)^t}{n}\equiv x \pmod{998244353} \]即
\[(n-1)^t\equiv n(x+1)-1\pmod{998244353} \]當\(t\)為偶數的時候
\[1+\frac{-1+(n-1)^t}{n}\equiv x \pmod{998244353} \]即
\[(n-1)^t\equiv n(x-1)+1\pmod{998244353} \]此時兩個式子都是\(A^x\equiv B\pmod{p}\)這種形式的高次同餘方程,可以使用"BSGS"演算法較快解決(演算法複雜度:\(O(\sqrt{p})\))。
程式碼:
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
typedef long long Lint;
const Lint mod = 998244353;
const Lint HashMod = 100007;
Lint fpow(Lint a, Lint b, Lint p) {
Lint res = 1;
for (; b; b >>= 1) {
if (b & 1) res = res * a % p;
a = a * a % p;
}
return res;
}
struct HashTable {
struct Line {
Lint u, v, next;
} e[1000000];
Lint h[HashMod], cnt;
void Add(Lint u, Lint v, Lint w) {
e[++cnt] = (Line){w, v, h[u]};
h[u] = cnt;
}
void Clear() {
memset(h, 0, sizeof(h));
cnt = 0;
}
void Hash(Lint x, Lint k) {
Lint s = x % HashMod;
Add(s, k, x);
}
Lint Query(Lint x) {
Lint s = x % HashMod;
for (Lint i = h[s]; i; i = e[i].next)
if (e[i].u == x) return e[i].v;
return -1;
}
} Hash;
Lint Solve(Lint y, Lint z, Lint p, int r) {
if (y % p == 0) {
return -1;
}
y %= p;
z %= p;
if (z == 1) {
return 0;
}
Lint m = sqrt(p) + 1;
Hash.Clear();
for (Lint i = 0, t = z; i < m; ++i, t = 1ll * t * y % p) Hash.Hash(t, i);
for (Lint i = 1, tt = fpow(y, m, p), t = tt; i <= m + 1; ++i, t = 1ll * t * tt % p) {
Lint k = Hash.Query(t);
if (k == -1) continue;
return i * m - k;
}
return -1;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
Lint n, x;
scanf("%lld%lld", &n, &x);
Lint res1, res2;
res1 = Solve(n - 1, (n * (x + 1) % mod + mod - 1) % mod, mod, 1);
res2 = Solve(n - 1, (n * (x + mod - 1) % mod + 1) % mod, mod, 0);
if (res1 % 2 == 0) res1 = -1;
if (res2 % 2 == 1) res2 = -1;
if (res1 == -1 && res2 == -1) {
puts("-1");
} else if (res1 == -1) {
printf("%lld\n", res2);
} else if (res2 == -1) {
printf("%lld\n", res1);
} else {
printf("%lld\n", min(res1, res2));
}
}
return 0;
}