其他分享
首页 > 其他分享> > [dp 记录] abc258Ex Odd Steps

[dp 记录] abc258Ex Odd Steps

作者:互联网

题意转化:给定 \(n\) 个整数和 \(S\),选一个从小到大排序的数列,\(0\) 和 \(S\) 必选,使相邻两数奇偶性不同,给出的 \(n\) 个数不能选。求方案数。
\(S \leq 10^{18},n \leq 10^5\)

看着非常 \(dp\),但是 \(S\) 极大,于是就是矩乘优化 \(dp\) 了。

令 \(dp_i\) 表示所选数均 \(\leq i\) 的情况,但又需要知道奇偶性以转移,于是 \(dp_{i,0/1}\) 表示所选数最大为 \(i\),所选最大数膜 \(2\) 余数为 \(i+0/1\) 的情况。此时,我们要求的是 \(dp_{i-1,0}\),因为最后还要选 \(S\) 出来。这样转化,我们看着丢失了直接获得答案的能力,但与此相比,我们可以以 \(O(1)\) 而非 \(O(n)\) 的代价递推,并仍能通过 \(O(1)\) 的代价获得答案。

\[\left\{ \begin{array}{ll} dp_{i,0} & \gets & dp_{i-1,1} + dp_{i-1, 0} \cdot [\text{if i could be chosen}] \\ dp_{i,1} & \gets & dp_{i-1,0} \end{array} \right. \]

将 \(n\) 个 \(a_i\) 作为分界,两个 \(a_i\) 之间用矩乘转移,否则朴素转移,即得。

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <initializer_list>
#define LL long long
using namespace std;
const int M = 100005, mod = 998244353;
struct matrix{
    int a[2][2], n, m;
    matrix() {}
    matrix(int n_, int m_) {n = n_; m = m_; memset(a, 0, sizeof(a));}
    matrix(int n_) {
        n = m = n_; memset(a, 0, sizeof(a));
        for(int i = 0; i < n; i++) a[i][i] = 1;
    }
    matrix(initializer_list<initializer_list<int>> list){
        n = list.size(); int l = 0;
        for(auto i : list){
            int v = 0; m = i.size();
            for(auto j : i) a[l][v++] = j;
            ++l; 
        }
    }
    int* operator [] (int i){
        return a[i];
    }
    matrix operator * (const matrix &tmp) {
        matrix t(n, tmp.m);
        for(int i = 0; i < n; i++)
            for(int j = 0; j < t.m; j++)
                for(int k = 0; k < m; k++)
                    t[i][j] = (t[i][j] + 1ll * a[i][k] * tmp.a[k][j] % mod) % mod;
        return t;
    }
    void print(string s){
        cout << s << ":\n";
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++) printf("%d ", a[i][j]);
            printf("\n");
        }
    }
};
matrix qpow(matrix a, LL b){
    matrix ans(a.n);
    for(; b; b >>= 1){
        if(b & 1) ans = ans * a;
        a = a * a;
    }
    return ans;
}
int n; LL s, a[M];
int main(){
    scanf("%d %lld", &n, &s);
    for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    matrix dp({{1, 0}}); matrix t({{1, 1}, {1, 0}});
    for(int i = 1; i <= n; i++){
        matrix x = dp * qpow(t, a[i] - a[i-1] - 1);
        dp[0][1] = x[0][0]; dp[0][0] = x[0][1];
    }
    dp = dp * qpow(t, s - a[n] - 1);
    printf("%d\n", dp[0][0]);
}

标签:matrix,int,list,++,abc258Ex,Steps,include,Odd,dp
来源: https://www.cnblogs.com/purplevine/p/16456910.html