1. 程式人生 > 其它 >[dp 記錄]agc013E Placing Squares

[dp 記錄]agc013E Placing Squares

什麼組合意義都不是給人看的,來點人能想到的題解

題意:

\(\displaystyle f_i = \begin{cases} 1 & i=0\\ \sum\limits_{j=1}^i f_j (i-j)^2 & i \not\in S \\ 0 & i \in S \end{cases}\)

給定 \(S,|S| \leq 10^5\),求 \(f(n),n\leq 10^9\)

注意到這裡的資訊轉移是很固定的,即是說,確定一個起始值和一個轉移方式後,每個 \(f_j\) 其實是比較容易確認的,也是容易用數學方法表示的。

若能找到類似矩乘之類能快速遞推的式子,即可像 abc258ex 那樣,整段遞推,邊界手動轉移,做到 \(O(m \log n)\)

來化一化式子。

\[\begin{aligned} f_j &= \sum_{j\leq i} f_j (i-j)^2 \\ &= \sum_{j < i} f_j(i-j-1)^2 + \sum_{j < i} f_j (i-j-1) + \sum_{j \leq i} f_j \\ \end{aligned} \]

後面呈現了降次,很好!

\[\begin{cases}s_{2,i}=\sum\limits_{j \leq i} f_j (i-j)^2 \\ s1_i=\sum\limits_{j \leq i} f_j(i-j) \\ s0_i=\sum\limits_{j \leq i} f_j \end{cases} \]

則當 \(i\)

不為標記點

\[\begin{cases} s_{0,i} = s_{0,{i-1}} + s_{2,{i-1}} \\ s_{1,i} = s_{1,{i-1}} + s_{2,{i-1}}+s_{0,{i-1}} \\ s_{2,i} = s_{2,i-1} + 2s_{1,i}+ 2s_{0,{i-1}} \end{cases} \]

否則

\[\begin{cases} s_{0,i} = s_{0,i-1} \\ s_{1,i} = s_{1,i-1} + s_{0,i-1} \\ s_{2,i} = s_{2,i-1} + 2s_{1,i-1} + s_{0,i-1} \end{cases} \]
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <initializer_list>
#define LL long long
using namespace std;
const int M = 100005, mod = 1000000007;
struct matrix{
    int a[3][3], 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("%lld %d", &s, &n);
    for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    matrix dp(3); matrix t({{1, 1, 1}, {0, 1, 2}, {1, 1, 2}});
    matrix t2({{1, 1, 1}, {0, 1, 2}, {0, 0, 1}}); 
    a[0] = -1;
    for(int i = 1; i <= n; i++){
        matrix x = dp * qpow(t, a[i] - a[i-1] - 1);
        dp = x * t2;
    }
    dp = dp * qpow(t, s - a[n] - 1);
    printf("%d\n", dp[0][2]);
}