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的转移矩阵,感觉很稳……

长这样:

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

转移矩阵长这样:

\begin{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("\n"))
            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\n", 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\n", sum, inv);
        printf("%lld\n", sum * inv % mod);
    }    
    return 0;
}

感觉还挺有趣的……

 

posted @ 2018-08-13 09:52  CzxingcHen  阅读(214)  评论(0编辑  收藏  举报