P8356 「WHOI-1」人赢计数 题解

· · 题解

思路

一看到这题,就想到了 dp 的做法。

我们令 dp_{i,j} 表示从 a_0a_{i+j} 共有 i+xj+y 且满足题目条件的不同的数列的个数。

考虑每次 +x+y,不难列出状态转移方程 dp_{i,j}=dp_{i,j-1}+dp_{i-1,j}。但需要考虑一种特殊情况,当 xi+yj\bmod p=0 时(即 a_{i+j}\bmod p=0),需要令 dp_{i,j}=0

但是这样空间复杂度是 O(n^2) 的,所以需要使用滚动数组,将第一维整体模 2 即可。

注意:若 x=y,则只有一种可能的序列,直接判断数列 a 是否符合要求即可。

\text{AC Code}

#include <bits/stdc++.h>
using namespace std;
int dp[2][10010];
const int mod = 1e9 + 7;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        int n, p, x, y, ans = 0;
        cin >> n >> p >> x >> y;
        if (x == y)
        {
            bool flag = false;
            for (int i = 1; i <= n; i++) if (1ll * i * x % p == 0)
            {
                flag = true;
                break;
            }
            cout << (flag ? 0 : 1) << endl;
            continue;
        }
        dp[0][0] = 1;
        for (int i = 0; i <= n; i++) for (int j = 0; i + j <= n; j++)
        {
            if (i == 0 && j == 0) continue;
            if ((1ll * i * x + 1ll * j * y) % p != 0)
            {
                if (i == 0) dp[i & 1][j] = dp[i & 1][j - 1];
                else if (j == 0) dp[i & 1][j] = dp[i & 1 ^ 1][j];
                else dp[i & 1][j] = (dp[i & 1 ^ 1][j] + dp[i & 1][j - 1]) % mod;
            }
            else dp[i & 1][j] = 0;
            if (i + j == n) ans = (ans + dp[i & 1][j]) % mod;
        }
        cout << ans << endl;
    }
    return 0;
}