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})
可列出方程组

[ egin{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
", ans);
        else if(ans == -1) printf("%lld
", res);
        else printf("%lld
", 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;
}
原文地址:https://www.cnblogs.com/ZX-GO/p/15039734.html