Hướng dẫn giải của Bedao Regular Contest 14 - KSUM


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.

Tác giả: bedao

Subtask 1: Trong Subtask này, ta giả sử ~\{b_1,b_2,...,b_{r-l+1}\} = \{a_l, a_{l+1},...a_r\}~. Sử dụng quy hoặch động như sau:

~f(i, j) =~ Tổng giá trị của các dãy con kích thước ~j~ của ~\{b_1,b_2,...,b_i\}~

Dễ dàng nhận thấy ~f(0,0)=1~. Khi đó có hai trường hợp xảy ra:

  • Tổng các dãy không chứa ~b_i~ là ~f(i-1,j)~
  • Tổng các dãy chứa ~b_i~ là ~f(i-1,j)\times b_i~

~\Rightarrow~ ~f(i, j) = f(i - 1, j) + f(i - 1, j - 1) \times b_i~

Subtask 2: Trong Subtask này, ta cũng vẫn giả sử ~\{b_1,b_2,...,b_{r-l+1}\} = \{a_l, a_{l+1},...a_r\}~. Ta có ~b_i\le 2~, gọi số lượng ~b_i = 2~ là ~x~; ta suy ra tổng giá trị các dãy độ dài ~k~ là:

~\sum_{i=0}^{\min(k,x)} C_x^i\times2^i \times C_{(r-l+1)-x}^{k-i}\times 1^{k-i}~

Subtask 3: Xét hai dãy ~x=\{x_1,x_2,...,x_m\}~, ~y=\{y_1,y_2,...,y_n\}~ và dãy ~z=\{x_1,x_2,...,x_m,y_1,...,y_n\}~. Gọi:

  • ~f_x(k)=~ Tổng giá trị các dãy con kích thước ~k~ của ~x~
  • ~f_y(k)=~ Tổng giá trị các dãy con kích thước ~k~ của ~y~
  • ~f_z(k)=~ Tổng giá trị các dãy con kích thước ~k~ của ~z~

Khi đó ta có khẳng định:

~f_z(K)=\sum_{k=0}^K f_x(k)\times f_y(K-k)~

Vậy, ta sẽ sử dụng một cây phân đoạn (Segment Tree) để lưu trữ hàm mục tiêu. Trên một node ~id~ quản lí đoạn ~[l, r]~ sẽ lưu mục mảng hàm mục tiêu cho đoạn con ~a[l..r]~ tương ứng.

Code mẫu

#include <bits/stdc++.h>
using namespace std;
#define fastIO ios_base::sync_with_stdio(false), cin.tie(NULL);
#define FF first
#define SS second
#define eps 1e-9
#define PI aocs(-1.0)
// VECTOR (6)
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(), (x).end()
#define lb lower_bound
#define ub upper_bound
#define uniq(x) sort(all((x))), (x).resize(unique(all((x))) - (x).begin());
// BIT (6)
#define BIT(x, i) (((x)>>(i))&1)
#define MASK(i) (1LL<<(i))
#define CNTBIT(x) __builtin_popcountll(x)
#define ODDBIT(x) __builtin_parityll(x)
#define SUBSET(big, small) (((big)&(small))==(small))
#define FIRSTBIT(x) __builtin_ctzll(x)
//typedef
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, ll> ii;

/* */
template <class T>
bool minimize(T &a, const T &b) {
    if(a > b) {a = b; return 1;}
    return 0;
}
template <class T>
bool maximize(T &a, const T &b) {
    if(a < b) {a = b; return 1;}
    return 0;
}
/* */

/* CODE BELOW */
const int N = 1e5 + 7, M = 1e9 + 7;
const int MOD = 1e9 + 7;
const int oo = 1e9 + 7;

const int K = 20 + 1;

int n, q, k;

int add(int a, int b) {
    a+= b; if(a>= MOD) a-=MOD;
    return a;
}

void upd(int &a, int b) {
    a+= b; if(a>=MOD) a-=MOD;
}

int mul(int a, int b) {
    return (1LL * a * b) % MOD;
}

struct Node {
    int _dp[K];
    Node() {
        for(int i = 0; i < K; i++) {
            _dp[i] = 0;
        }
    }
    int &operator[] (int index) {
        return _dp[index];
    }
    const int &operator[] (int index) const {
        return _dp[index];
    }
};


Node add(const Node &l, const Node &r) {
    Node ans;
    for(int i=1;i<=k;i++) {
        for(int j=0;j<i;j++) {
            upd(ans[i], mul(l[j], r[i-j]));
        }
        upd(ans[i], add(l[i], r[i]));
    }
    return ans;
}

class SegmentTree {
private:
    int n;
    vector<Node> st;
private:
    void update(int idx, int l0, int r0, int p, int v) {
        if(l0 > r0 || p < l0 || p > r0) return;
        if(l0 == p && r0 == p) {
            st[idx][1] = v;
            return;
        }
        int mid = (l0+r0)/2;
        update(idx*2, l0, mid, p, v);
        update(idx*2+1, mid+1, r0, p, v);

        st[idx] = add(st[idx * 2], st[idx * 2 + 1]);
    }
    Node query(int idx, int l0, int r0, int l, int r) {
        if(l0 > r0 || r < l0 || l > r0) return Node();
        if(l <= l0 && r0 <= r) {
            return st[idx];
        }
        int mid = (l0 + r0)/2;
        Node a = query(idx * 2, l0, mid, l, r);
        Node b = query(idx * 2 + 1, mid + 1, r0, l, r);
        return add(a, b);
    }
public:
    SegmentTree(int _n = 0):n(_n) {
        st.assign(4 * _n + 7, Node());
    }
    void update(int p, int v) {
        update(1, 1, n, p, v);
    }
    int query(int l, int r) {
        return query(1, 1, n, l, r)[k];
    }
};

SegmentTree IT;

signed main() {
    fastIO;
    cin >> n >> k;
    IT = SegmentTree(n);
    for(int i=1;i<=n;i++) {
        int v; cin >> v;
        IT.update(i, v);
    }

    cin >> q;
    for(int i=1;i<=q;i++) {
        int type; cin >> type;
        if(type == 1) {
            int l, r;
            cin >> l >> r;
            cout << IT.query(l, r) << endl;
        } else {
            int idx, x;
            cin >> idx >> x;
            IT.update(idx, x);
        }
    }


    return 0;
}

Bình luận

Hãy đọc nội quy trước khi bình luận.


Không có bình luận tại thời điểm này.