HDU 6956. Pass! 题解
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^2-(n-2)r-(n-1)=0
\]
解得
\[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\),有
\[\begin{split}
-C_1+(n-1)C_2&=0 \\
C_1+(n-1)^2C_2&=n-1
\end{split}
\]
解得
\[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;
}