USACO 2020 January Contest, Platinum Problem 2. Non-Decreasing Subsequences

题目链接:http://usaco.org/index.php?page=viewproblem2&cpid=997

 

题解:矩阵在DP中的应用。

  对于区间1-i,我们假设我们的合法子序列方案数为∑f[i][0][j], f[i][j][k] 就表示在这个区间里以j开头以k结尾的方案数。也就说我们有N个K*K的矩阵。但很明显这样是不满足区间减法的。我们可以发现,每加入一个元素x,我们有一个贡献矩阵把矩阵f[i-1]转移到f[i],假设这个贡献矩阵是A[i],那么f[i]=A[i]*A[i-1]......*A[1],假如我想知道区间的贡献矩阵之积,我们可以用“逆矩阵”。我们设invf[i]=A'[1]*A'[2].....*A'[i],那么区间的贡献矩阵是f[R]*invf[L-1],这样我们可以做到O((Q+N)K^3),这只能过一部分数据。研究一下这些贡献矩阵发现,它是一个三角矩阵,并且只有一行(或者一列,取决于你的贡献矩阵是左乘还是右乘)和单位矩阵不一样,也就说我们可以在预处理f[i]和invf[i]的时候把矩阵乘法加速到K^2,然后答案的区间矩阵我们只需要知道一列,然后我们可以通过预处理加速到K。总的时间复杂度是O(NK^2+QK)。

#include <bits/stdc++.h>

using namespace std;

const int modu = 1e9 + 7;
typedef long long ll;
const ll inverse2 = (1e9+8)/2;
ll f[22][22], invf[22][22];
ll pre[50005][22], ipre[50003][22];
int N, K, Q, cur;
int A[50003];

int main() {
    freopen("nondec.in", "r", stdin);
    freopen("nondec.out", "w", stdout);
    scanf("%d%d", &N, &K);
    memset(f, 0, sizeof(f));
    memset(invf, 0, sizeof(invf));
    for (int i = 0; i <= K; ++i) f[i][i] = invf[i][i] = 1;
    ipre[0][0] = 1;
    for (int i = 1; i <= N; ++i) {
        scanf("%d", &A[i]);
      //手动模拟矩阵乘法,因为有系数2,所以每个贡献矩阵左乘拆成两种基本行变换,把A[i]行*2,和把前面的行加到这一行。
for (int j = 0; j < A[i]; ++j) { ll sumf = 0; for (int k = 0; k < A[i]; ++k) { sumf = (sumf + f[k][j]*inverse2) % modu; } f[A[i]][j] = (f[A[i]][j] + sumf) % modu; } for (int j = 0; j <= K; ++j) f[A[i]][j] = f[A[i]][j]*2 % modu; for (int j = 0; j <= K; ++j) for (int k = 0; k <= K; ++k) pre[i][j] = (pre[i][j] + f[k][j]) % modu;
      //右乘可以看成基本列变换
for (int j = 0; j <= K; ++j) invf[j][A[i]] = invf[j][A[i]]*inverse2 % modu; for (int j = A[i]; j <= K; ++j) { for (int k = 0; k < A[i]; ++k) invf[j][k] = (invf[j][k] - invf[j][A[i]]) % modu; } for (int j = 0; j <= K; ++j) ipre[i][j] = invf[j][0]; } scanf("%d", &Q); while (Q--) { int L, R; scanf("%d%d", &L, &R); ll ans = 0; for (int i = 0; i <= K; ++i) ans = (ans + pre[R][i]*ipre[L-1][i]) % modu; printf("%lld\n", (ans + modu) % modu); } return 0; }

 

posted @ 2020-03-16 22:26  albertxwz  阅读(375)  评论(0编辑  收藏  举报