• Luogu U15118 萨塔尼亚的期末考试(fail)


    感觉...昨天是真的傻...  

    题意

    T个询问,每个询问给一个n,求

    $ frac{sum_{n}^{i = 1}Fib_{i} * i}{n * (n + 1) / 2} $

    Fib是斐波那契数列,对998244353取模

    然后...我昨天把n乘了之后就忘记取模了...

    30分做法

    设$ a_{i} = i * Fib_{i} $, 有$ a_{i} = a_{i - 1} + a_{i - 2} + Fib_{i - 1} + Fib_{i - 2} $,然后就写了一个5*5的转移矩阵,感觉很稳……

    长这样:

    egin{bmatrix}
    Fib_{i} & Fib{i - 1} & a_{i} & a_{i - 1} & sum_{i - 1}
    end{bmatrix}

    转移矩阵长这样:

    egin{bmatrix}
    1 & 1 & 1 & 0 & 0 \
    1 & 0 & 2 & 0 & 0\
    0 & 0 & 1 & 1 & 1\
    0 & 0 & 1 & 0 & 0\
    0 & 0 & 0 & 0 & 1
    end{bmatrix}

    虽然这个东西也过了几万组对拍,但是我喜闻乐见地把std也顺便写挂了(捂脸),所以这两个东西都只有10分... 

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const ll mod = 998244353;
    
    int testCase;
    ll n;
    
    struct Matrix {
        ll l1, l2, s[5][5];
        
        inline void init() {
            l1 = l2 = 0;
            memset(s, 0, sizeof(s));
        }
        
        friend Matrix operator * (const Matrix a, const Matrix b) {
            Matrix res;
            res.init();
            res.l1 = a.l1, res.l2 = b.l2;
            for(int i = 0; i < a.l1; i++)
                for(int j = 0; j < b.l2; j++)
                    for(int k = 0; k < a.l2; k++)
                        res.s[i][j] = (res.s[i][j] + a.s[i][k] * b.s[k][j] % mod) % mod;
            return res;
        }
            
        inline Matrix pow(Matrix a, ll b) {
            Matrix res = *this;
            for(; b > 0; b >>= 1) {
                if(b & 1) res = res * a;
                a = a * a;
            }
            return res;
        }
        
        inline void print() {
            for(int i = 0; i < l1; i++, printf("
    "))
                for(int j = 0; j < l2; j++)
                    printf("%lld ", s[i][j]);
        }
        
    } f;
    
    inline ll pow(ll x, ll y) {
        ll res = 1;
        for(x %= mod; y > 0; y >>= 1) {
            if(y & 1) res = res * x % mod;
            x = x * x % mod;
        }
        return res;
    }
    
    inline ll solve() {
        if(n == 1) return 1LL;
        if(n == 2) return 3LL;
        
        Matrix g;
        g.init();
        g.l1 = 1, g.l2 = 5;
        g.s[0][0] = g.s[0][1] = g.s[0][3] = 1;
        g.s[0][4] = 1;
        g.s[0][2] = 2;
    //    g.print();
        
        g = g.pow(f, n - 1);
        
    //    g.print();
            
        return g.s[0][4];
    }
    
    int main() {
        f.init();
        f.l1 = f.l2 = 5;
        f.s[0][0] = f.s[0][1] = f.s[0][2] = 1;
        f.s[1][0] = f.s[2][2] = f.s[2][3] = f.s[2][4] = 1;
        f.s[3][2] = f.s[4][4] = 1;//f.s[4][2] = 1;
        f.s[1][2] = 2;
        
    //    f.print();
    
        for(scanf("%d", &testCase); testCase--; ) {
            scanf("%lld", &n);
            ll tmp = n * (n + 1) / 2;
            ll inv = pow(tmp, mod - 2);
            ll sum = solve();
            printf("%lld
    ", inv * sum % mod); 
        }  
        return 0;
    }

    100分做法  

    找规律题惹不起a... 

    $sum_{n} = n * Fib_{n + 2} - Fib_{n + 3} + 2$

    所以就变成一个斐波那契了
    并不能推导出来...   

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const ll mod = 998244353;
    
    int testCase;
    ll n;
    
    struct Matrix {
        ll s[3][3];
        
        inline void init() {
            memset(s, 0, sizeof(s));
        }
        
        friend Matrix operator * (const Matrix a, const Matrix b) {
            Matrix res;
            res.init();
            for(int i = 1; i <= 2; i++)
                for(int j = 1; j <= 2; j++)
                    for(int k = 1; k <= 2; k++)
                        res.s[i][j] = (res.s[i][j] + a.s[i][k] * b.s[k][j] % mod) % mod;
            return res; 
        }
        
        inline Matrix pow(ll b) {
            Matrix res, a = *this;
            res.init();
            for(int i = 1; i <= 2; i++) res.s[i][i] = 1;
            for(; b > 0; b >>= 1) {
                if(b & 1) res = res * a;
                a = a * a;
            }
            return res;
        }
        
    } f;
    
    inline ll pow(ll a, ll b) {
        ll res = 1;
        for(; b > 0; b >>= 1) {
            if(b & 1) res = res * a % mod;
            a = a * a % mod;
        }
        return res;
    }
    
    inline ll solve() {
        Matrix res = f.pow(n + 2);
        return (res.s[1][2] * n % mod - res.s[1][1] + 2 + mod) % mod; 
    }
    
    int main() {
        f.init();
        f.s[1][1] = f.s[1][2] = f.s[2][1] = 1;
        for(scanf("%d", &testCase); testCase--; ) {
            scanf("%lld", &n);
            ll inv = pow((n * (n + 1) / 2)% mod, mod - 2);
            ll sum = solve();
    //        printf("%lld %lld
    ", sum, inv);
            printf("%lld
    ", sum * inv % mod);
        }    
        return 0;
    }

    感觉还挺有趣的……

  • 相关阅读:
    【题解】CodeChef
    【题解】AT1984 Wide Swap(拓扑排序)
    【题解】CF917D Stranger Trees(prufer序列+二项式反演)
    【题解】UVA
    【题解】P3980 [NOI2008]志愿者招募(费用流求线性规划)
    【题解】AT2064 Many Easy Problems(转换+NTT)
    【题解】AT1983 BBQ Hard (格路)
    【总结】不同卷积如何来搞
    【瞎讲】 Cayley-Hamilton 常系数齐次线性递推式第n项的快速计算 (m=1e5,n=1e18)
    计算几何小结计算几何小结
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9466398.html
Copyright © 2020-2023  润新知