zoukankan      html  css  js  c++  java
  • cf1106F Lunar New Year and a Recursive Sequence

    传送门

    根据公式可以退出(i>k)时的(f_i = f_i^{g_i}), 其中(g_i)是存在一个递推式(g_i = sum_{j = 1}^kb_j imes g_{i - j})
    已知(k in [1,100]),那么就可以用矩阵快速幂求出(f_n)的幂(k),那么

    (f_n = f_k^k equiv m(mod 998244353 ))

    相当于变成了(x^aequiv m(mod 998244353 )),其中(a, m)已知。

    那不就是N次剩余吗?试了下洛谷的板子,mle了。。。

    其实这里可以进行优化,对于N次剩余来说,如果模存在离散对数,那么可以进行化简

    (a imes ind_g x equiv ind_g m(mod P - 1))

    其中(x = g^{ind_g x + P - 1 } equiv (mod P))

    其中g就是模(P)的一个原根。
    (ind_g m)(m)在模的一个原根(g)下的离散对数
    利用同余方程就可以解出(ind_g x)的值,最后再代换回来就行了

    注意一点就是用矩阵快速幂求幂,且模是质数,那么幂就去欧拉降幂,模(P - 1)

    #include <bits/stdc++.h>
    #define ll long long
    #define CASE int Kase = 0; cin >> Kase; for(int kase = 1; kase <= Kase; kase++)
    using namespace std;
    template<typename T = long long> inline T read() {
        T s = 0, f = 1; char ch = getchar();
        while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();} 
        return s * f;
    }
    const int N = 100 + 5, M = 100 + 5, MOD = 1e9 + 7, CM = 998244353, INF = 0x3f3f3f3f, g = 3;
    struct Matrix{
        int n, m;
        int a[M][M];
        Matrix(int n = 0, int m = 0):n(n),m(m){memset(a, 0, sizeof(a));};
        Matrix operator * (const Matrix &b) const {
            Matrix ans(n,b.m);
            for(int i = 0; i < n; i++)
                for(int j = 0; j < b.m; j++)
                    for(int k = 0; k < m; k++)
                        ans.a[i][j] = (ans.a[i][j] + 1ll * a[i][k] * b.a[k][j] % (CM - 1)) % (CM - 1);
            return ans;
        }
    };
    Matrix ksm(Matrix a, int b){
        Matrix ans(a.n, a.m);
        for(int i = 0; i < max(a.n, a.m); i++) ans.a[i][i] = 1;
        while(b) {
            if(b & 1) ans = ans * a;
            a = a * a;
            b >>= 1;
        }
        return ans;
    }
    int b[N];
    ll cal(int n, int k){
        Matrix base(k, k);
        for(int i = 0; i < k; i++) base.a[0][i] = b[i + 1];
        for(int i = 1; i < k; i++) base.a[i][i - 1] = 1;
        Matrix ans(k, 1);
        ans.a[0][0] = 1;
        base = ksm(base, n - k);
        ans = base * ans;
        return ans.a[0][0]; 
    }
    ll qpow(ll a, ll b, ll p){
        ll ans = 1; a %= p;
        while(b){
            if(b & 1) ans = ans * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return ans;
    }
    map<int,int>mp;
    int bsgs(int x, int P){
        int m = sqrt(P) + 1; mp.clear();
        for(int i = 0, res = x; i < m; ++i, res = 1ll * res * g % P) mp[res] = i;
        for(int i = 1, tmp = qpow(g, m, P), res = tmp; i <= m + 1; ++i, res = 1ll * res * tmp % P)
            if(mp.count(res)) return i * m - mp[res];
        return 0;
    }
    void ex_gcd(ll a, ll b, ll &d, ll &x, ll &y){
        if(!b){
            d = a, x = 1, y = 0;
            return;
        }
        ex_gcd(b,a % b,d,y,x);
        y -= x * (a / b);
    }
    ll gcd(ll a, ll b){
        return b == 0 ? a : gcd(b, a % b);
    }
    void cal(ll a, ll &x, ll b, ll m){ // 求ax == b (mod m) 的解x
        ll d = gcd(a, m), y = 0;
        if(b % d) return x = -1, void(0);
        ex_gcd(a, m, d, x, y);
        x = (b / d * x + m / d) % (m / d); // 最小正整数解
    }
    void solve(int kase){
        int k = read();
        for(int i = 1; i <= k; i++) b[i] = read();
        int n = read(), m = read();
        ll qpower = cal(n, k);
        ll ans = 0;
        cal(qpower, ans, bsgs(m, CM), CM - 1);
        if(ans == -1) printf("-1
    ");
        else printf("%lld
    ", qpow(g, ans + CM - 1, CM));
    }
    const bool DUO = 0;
    int main(){
        clock_t start, finish; double totaltime; start = clock();
        if(DUO) {CASE solve(kase);} else solve(1);
        finish = clock(); 
        #ifdef ONLINE_JUDGE
            return 0;
        #endif
        printf("
    Time: %lfms
    ", (double)(finish - start) / CLOCKS_PER_SEC * 1000);
        return 0;
    }
    
    I‘m Stein, welcome to my blog
  • 相关阅读:
    (原创)代码分析-DataGrid实现增删(带提示)改和分页
    (原创)webform页面间传值的特殊方法
    (原创)如何把数据放到web不能访问的文件夹中并给用户下载?
    MediaWiki如何重置用户密码
    伟大的程序员是怎样炼成的?
    Java多线程(一)、多线程的基本概念和使用
    Android杂谈Activity、Window、View的关系
    Android LayoutInflater学习
    10条不可不知的手机礼仪 看看你犯过哪几项?
    Java支持的字符集[Code]
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14386363.html
Copyright © 2011-2022 走看看