2021杭电多校1 HDU6956-Pass!【特征方程求解数列通向式+BSGS】

题目链接
赛中知道了\(f(i)=(n-2)*f(i-1)+(n-1)*f(i-2)\),然后考虑到矩阵上去了,然后歪了。
思路
看了题解才知道,可以将上式通过特征方程求解数列的通项公式求得
\(f(t)=\frac{((n-1)^t+(n-1)*(-1)^t)}{n}=x (\mod 998244353)\)
写一下是如何推导出来的。
已知\(a_i=(n-2)*a_{i-1}+(n-1)*a_{i-2}\),移项并构造一个类似等比数列的东西:
\(a_i-x*a_{i-1}=(a_{i-1}-x*a_{i-2})*y\)
那么可以发现
\(a_i=(x+y)*a_{i-1}-x*y*a_{i-2}\)
\(c_1=x+y,c_2=-x*y\)其特征方程为:
\(x^2=c1*x+c2\)\(x^2=(n-2)*x+(n-1)\)
求解可得 \(x_1=-1,x_2=n-1\)
注意到原式子,代入\(x1,x2\)可通过
\(x+y=n-2,-x*y=n-1\)
求得\(y1=n-1,y2=-1\)

由上文提到的这个式子 \(a_i-x*a_{i-1}=(a_{i-1}-x*a_{i-2})*y\) 通过移项得\(\frac{a_i-x*a_{i-1}}{a_{i-1}-x*a_{i-2}}=y\),这是一个首项为\(a_1-x*a_0\),公比为\(y\)得等比数列,即:
\(a_i-x*a_{i-1}=(a_1-x*a_0)*y^{i-1}\)
可列出方程组

\[ \begin{cases} a_i-x_1*a_{i-1}=(a_1-x_1*a_0)*y_1^{i-1} \\ a_i-x_2*a_{i-1}=(a_1-x_2*a_0)*y_2^{i-1} \\ \end{cases} \]


\(a_i=\frac{(a_1-x_1*a_0)*y_1^{i-1}*x_2-(a_1-x_2*a_0)*y_2^{i-1}*x_1}{x_2-x_1}\)
已知\(a_0=1,a_1=0,x_1=-1,x_2=n-1,y_1=n-1,y_2=-1\),代入可得:
\(a_i=\frac{(n-1)^i+(n-1)*(-1)^i}{n}\)
那么就是式子\(f(t)=\frac{((n-1)^t+(n-1)*(-1)^t)}{n}\)
然后分奇偶BSGS即可。
代码

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
#define x first
#define y second
const int N = 1e3 + 10, M = 13331;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
#define gcd __gcd

unordered_map<int, int> Hash;

LL kpow(LL a, LL n) {
    LL res = 1;
    while(n) {
        if(n & 1) res = res * a % mod;
        n >>= 1;
        a = a * a % mod;
    }
    return res;
}

LL bsgs(LL a, LL b, LL p) {
    Hash.clear();
    a %= p; b %= p;
    if(b == 1) return 0;
    int k = sqrt(p) + 1;
    for(int i = 0, j = b % p; i < k; i++) {
        Hash[j] = i;
        j = (LL)j * a % p;
    }
    int ak = kpow(a, k);
    for(int x = 1, num = ak; x <= k; x++) {
        if(Hash.count(num)) return x * k - Hash[num];
        num = (LL)num * ak % p;
    }
    return -1;
}

void solve() {
    LL n, x;
    scanf("%lld%lld", &n, &x);
    if(x == 1) puts("0");
    else if(x == 0) puts("1");
    else {
        LL tmp = x;
        x = 1LL * x * n % mod + (n - 1);
        x = (x + mod) % mod;
        LL res = bsgs(n - 1, x, mod);
        if(res % 2 == 0) res = -1;

        x = tmp;
        x = 1LL * x * n % mod - (n - 1);
        x = (x + mod) % mod;
        LL ans = bsgs(n - 1, x, mod);
        if(ans & 1) ans = -1;

        if(res == ans && res == -1) puts("-1");
        else if(res == -1) printf("%lld\n", ans);
        else if(ans == -1) printf("%lld\n", res);
        else printf("%lld\n", min(res, ans));
    }
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    #endif // ONLINE_JUDGE

    int t; cin >> t; while(t--)
    solve();
    return 0;
}
posted @ 2021-07-21 15:29  这知识他不进我的脑子  阅读(223)  评论(0编辑  收藏  举报