一篇文章带你了解计数DP

1. 概念引入

计数动态规划(简称计数DP)是动态规划的一种应用领域,主要用于解决计数问题。计数问题是指需要计算某个特定事件的发生次数或满足特定条件的组合数目的问题。

计数 D P DP DP特点:

  • 数量较,常常要取模,计算过程中注意使用 l o n g long long l o n g long long
  • D P DP DP初始化边界条件的处理需要注意。
  • 统计组合数目就用到组合数逆元等相关知识。

2. 例题精讲

话不多说,我们直接看例题。

2.1 棋盘划分

题目链接

2.1.1 题目分析

对于5,我们有如下的划分:

  • 5
  • 4 + 1
  • 3 + 2
  • 3 + 1 + 1
  • 2 + 2 + 1
  • 2 + 1 + 1 + 1
  • 1 + 1 + 1 + 1 + 1

联系我们之前学过的知识点,很容易想到完全背包

2.1.1.1 完全背包复习

完全背包模型与01背包类似,与01背包的区别仅在于一个物品可以选取无限次,而非仅能选取一次。

完全背包代码:

#include 
using namespace std;
typedef pair PII;
#define int long long
#define endl '\n'
const int N = 3000;
int w[N], c[N], dp[N];
signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int m, n;
    cin >> m >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> w[i] >> c[i];
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            dp[j] = max(dp[j], dp[j - w[i]] + c[i]);
        }
    }
    return 0;
}

完全背包与01背包的代码实现区别:
v : 10 − 9 − 8 − 7 − 6 ∣ w [ i ] = 3 v: 10-9-8- 7 - 6 | w[i] = 3 v:109876∣w[i]=3
更新公式: d p [ l ] = f [ l − w [ i ] ] + v [ i ] dp[l]=f[l - w[i]] + v[i] dp[l]=f[lw[i]]+v[i]
变量 l l l倒序时:
更新的顺序: d p [ 10 ] , d p [ 9 ] , d p [ 8 ] , d p [ 7 ] dp[10],dp[9],dp[8],dp[7] dp[10],dp[9],dp[8],dp[7]
变量 l l l顺序时:
更新: d p [ 3 ] , d p [ 4 ] , d p [ 5 ] , d p [ 6 ] , d p [ 7 ] dp[3],dp[4],dp[5],dp[6],dp[7] dp[3],dp[4],dp[5],dp[6],dp[7]
差别:使用顺序的时候,每次更新采用这一轮被更新过的值

2.1.2 代码

下面附上代码

#include 
#define int long long
#define endl '\n'
using namespace std;
typedef pair PII;
const int N = 3000;
const int P = 1e9 + 7;
int f[N];
signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    f[0] = 1;
    for (int i = 1; i <= n; i++){
        for (int j = i; j <= n; j++){
            f[j] = (f[j] + f[j - i]) % P;
        }
    }
    cout << f[n] % P;
    return 0;
}

2.1.3 AC图片

一篇文章带你了解计数DP_第1张图片

2.2 序列重排

2.2.1 代码

#include 
using namespace std;
#define endl '\n'
#define int long long
#define PII pair
#define For(i, a, b) for (int i = a; i <= b; i++)
const int N = 1e6;
const int M = 1e4;
const int MOD = 998244353;
int n, a[N];
int x, y;
int fac[N], inv[N];
int dp[M][M];
int quick_power(int a, int k, int p)
{
    int ans = 1;
    while (k)
    {
        if (k & 1)
            ans = ans * a % p;
        k >>= 1;
        a = a * a % p;
    }
    return ans;
}
void init()
{
    inv[0] = inv[1] = 1;
    fac[0] = fac[1] = 1;
    for (int i = 2; i <= 200010; ++i)
    {
        fac[i] = (fac[i - 1] * i) % MOD;
        inv[i] = quick_power(fac[i], MOD - 2, MOD);
    }
}
int C(int n, int m)
{
    return fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
void problem_solved(){
    dp[0][0] = 1;
    For (i, 0, x){
        For (j, 0, y){
            if (i >= j){
                if (x - i >= y - j){
                    dp[i][j + 1] = (dp[i][j + 1] + dp[i][j]) % MOD;
                    dp[i + 1][j] = (dp[i + 1][j] + dp[i][j]) % MOD;
                }
            }
        }
    }
    cout << dp[x][y] << endl;
}
signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    init();
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        if (a[i] == 1)
        {
            x++;
        }
        else
        {
            y++;
        }
    }
    if (x <= y)
    {
        cout << C(y + 1, x) << endl;
        return 0;
    }
    problem_solved();
    return 0;
}

2.2.2 AC图片

一篇文章带你了解计数DP_第2张图片

3.结语

今天的文章就到这里啦,三连必回qwq!

你可能感兴趣的:(c++,c++)