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;
}