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;
}
posted @ 2021-07-21 17:48  聆竹听风  阅读(156)  评论(0)    收藏  举报