CF1316F Battalion Strength 题解

sto SoyTony orz

这题动态 DP 真能过(

排序后序列的子序列唯一对应原序列的子序列排序后的结果,所以先排序。

设 $f_i$ 表示前 $i$ 位的子序列的权值之和,则 $f_i=2f_{i-1}+a_i\sum\limits_{j=1}^{i-1}2^{j-1}a_j$,容易做到单次线性。

考虑动态 DP,则有:

$$ \begin{bmatrix} f_{i-1}&\sum\limits_{j=1}^{i-1}2^{j-1}a_j&2^{i-1} \end{bmatrix} \times \begin{bmatrix} 2&0&0\\ a_i&1&0\\ 0&a_i&2 \end{bmatrix} = \begin{bmatrix} f_i&\sum\limits_{j=1}^i2^{j-1}a_j&2^i \end{bmatrix} $$

每次单点修改相当于排序后序列上单点删除,单点插入,权值线段树维护之。

注意单点删除时矩阵不一定有逆,所以对每个值 $i$ 预处理 $i$ 的矩阵的 $[0,c_i]$ 次方,其中 $c_i$ 为 $i$ 在序列和修改中的总出现次数,

修改某值的出现次数时直接查表即可。

常数优化:注意到矩阵是下三角矩阵,所以矩阵乘法可以优化成 $10$ 次整数乘加。

复杂度 $O(n\log n)$,可以过。

#include <cstdio>
#include <vector>
#include <algorithm>
#define M 1000000007
#define H(x) lower_bound(b, b + p, x) - b + 1
using namespace std;
int P(long long x, int y)
{
    long long q = 1;
    for (; y; y >>= 1, x = x * x % M)
        if (y & 1)
            q = q * x % M;
    return q;
}
int n, m, p, a[600050], c[600050], b[600050], w[300050];
long long o;
struct Q
{
    int x, y;
} q[300050];
struct S
{
    int a[3][3];
    S()
    {
        for (int i = 0; i < 3; ++i)
            for (int j = 0; j <= i; ++j)
                a[i][j] = 0;
    }
    S operator*(S b)
    {
        S c;
        for (int i = 0; i < 3; ++i)
            for (int j = 0; j <= i; ++j)
            {
                long long q = 0;
                for (int k = j; k <= i; ++k)
                    q += 1ll * a[i][k] * b.a[k][j];
                c.a[i][j] = q % M;
            }
        return c;
    }
} R[600050 << 2];
vector<S> v[600050];
void B(int s, int t, int p)
{
    if (s == t)
        return void(R[p] = v[s][a[s]]);
    int m = s + t >> 1;
    B(s, m, p << 1);
    B(m + 1, t, p << 1 | 1);
    R[p] = R[p << 1] * R[p << 1 | 1];
}
void C(int l, int x, int s, int t, int p)
{
    if (s == t)
        return void(R[p] = v[s][x]);
    int m = s + t >> 1;
    if (l <= m)
        C(l, x, s, m, p << 1);
    else
        C(l, x, m + 1, t, p << 1 | 1);
    R[p] = R[p << 1] * R[p << 1 | 1];
}
int main()
{
    srand(388651);
    scanf("%d", &n);
    for (int i = o = 1; i <= n; ++i)
        scanf("%d", w + i), b[p++] = w[i], o = (o << 1) % M;
    scanf("%d", &m);
    for (int i = 0; i < m; ++i)
        scanf("%d%d", &q[i].x, &q[i].y), b[p++] = q[i].y;
    sort(b, b + p);
    p = unique(b, b + p) - b;
    for (int i = 1; i <= n; ++i)
        ++a[w[i] = H(w[i])], ++c[w[i]];
    for (int i = 0; i < m; ++i)
        ++c[q[i].y = H(q[i].y)];
    for (int i = 1; i <= p; ++i)
    {
        S z, q;
        for (int j = 0; j < 3; ++j)
            z.a[j][j] = 1;
        v[i].push_back(z);
        q.a[1][1] = 1;
        q.a[0][0] = q.a[2][2] = 2;
        q.a[1][0] = q.a[2][1] = b[i - 1];
        q.a[0][1] = q.a[0][2] = q.a[1][2] = q.a[2][0] = 0;
        for (int j = 1; j <= c[i]; ++j)
            v[i].push_back(v[i].back() * q);
    }
    B(1, p, 1);
    o = P(o, M - 2);
    printf("%d\n", R[1].a[2][0] * o % M);
    for (int i = 0; i < m; ++i)
    {
        C(w[q[i].x], --a[w[q[i].x]], 1, p, 1);
        C(w[q[i].x] = q[i].y, ++a[q[i].y], 1, p, 1);
        printf("%d\n", R[1].a[2][0] * o % M);
    }
    return 0;
}
posted @ 2023-08-22 09:46  5k_sync_closer  阅读(5)  评论(0编辑  收藏  举报  来源