1. 程式人生 > 其它 >HDU 6956. Pass! 題解

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\),有

\[-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;
}