📜  门|门CS 2012 |第 46 题(1)

📅  最后修改于: 2023-12-03 15:28:49.045000             🧑  作者: Mango

门|门CS 2012 |第 46 题

题目描述

在一个长 $n(n \leq 10^7)$ 的序列中,第 $i$ 个元素的取值范围是 $[1, m](m \leq 10^4)$,某些元素有固定的取值,已知这些固定值,请你求出完整序列的方案数。

输入格式

第一行包含三个整数 $n, m, k$,分别表示序列的长度,元素的取值范围和已知固定值的数量。

接下来 $k$ 行,每行包含两个整数 $pos, val$ 表示序列中第 $pos$ 个元素的值为 $val$。

输出格式

输出一个整数,表示完整序列的方案数对 $10^9 + 7$ 取模的结果。

数据范围

$1 \leq n, m \leq 10^4$ $1 \leq k \leq n$

温馨提示:本题的输出可能很大,请使用 64 位整数型。

题解

可以使用动态规划来计算方案数。设 $f_i$ 表示考虑到第 $i$ 个位置时的方案数,则有:

$$ f_i=\begin{cases} 1, &(i\leq k) \ 0, &(val_{pos_i}\neq 0 \land val_{pos_i}\neq a_i) \ f_{i-1}, &(a_i=0) \ f_{i-1}-f_{pos_i-1}\times (m-1), &(pos_i<i\land a_i=0) \ \end{cases} $$

其中 $val_i$ 表示已知固定值的取值,$pos_i$ 表示已知固定值的位置。

最终答案为 $f_n$。

代码实现
#include <iostream>
#include <cstring>

using namespace std;

typedef long long LL;
const int MOD = 1e9 + 7;
const int N = 10010;

int n, m, k;
int val[N], pos[N];
LL f[N], s[N];

int main()
{
    cin >> n >> m >> k;

    memset(val, -1, sizeof val);

    for (int i = 0; i < k; i ++ )
    {
        int x, y;
        cin >> x >> y;
        val[x - 1] = y - 1, pos[x - 1] = i;
    }

    f[0] = 1;
    s[0] = 1;
    for (int i = 1; i <= n; i ++ )
    {
        if (~val[i - 1] && val[i - 1] != i - 1) f[i] = 0;
        else if (~val[i - 1] && val[i - 1] == i - 1) f[i] = f[i - 1];
        else if (pos[i - 1] == 0) f[i] = f[i - 1] * m % MOD;
        else 
        {
            f[i] = (f[i - 1] - s[pos[i - 1] - 1] * (m - 1) % MOD) % MOD;
            f[i] += MOD, f[i] %= MOD;
        }
        s[i] = (s[i - 1] + f[i]) % MOD;
    }

    cout << f[n] << endl;

    return 0;
}

时间复杂度:$O(n)$