dp合集

  • 线性dp

[ABC216F] Max Sum Counting

想到了排序a,以及背包,但是看了下数据范围以为不可以背包,但是可以发现 $\sum_{i \in S} \space b_i$ 不会大于5000,所以可以背包

不能只开一维dp数组,设置为一维会导致很多个第 i 位位置状态叠在一起

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
typedef long long ll;

const int N = 5e3 + 5;
const int mod = 998244353;

struct Node{
    int x, y;
}a[N];

bool cmp(Node t1, Node t2){
    return t1.x < t2.x;
}

//dp数组不能设置为一维,设置为一维会导致很多个第i位位置状态叠在一起

int f[N][N][2];

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n; cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i].x;
    for(int i = 1; i <= n; i++) cin >> a[i].y;
    sort(a + 1, a + 1 + n, cmp);
    int ans = 0; f[0][0][0] = 1;
    for(int i = 1; i <= n; i++) {
        int val = a[i].y;
        for(int j = 0; j <= 5000; j++) {
            f[i][j][0] = (f[i - 1][j][0] + f[i - 1][j][1]) % mod;
            if(j - val >= 0)f[i][j][1] = (f[i - 1][j - val][0] + f[i - 1][j - val][1]) % mod;

        }
    }
    for(int i = 1; i <= n; i++) {
        int val = a[i].y, maxn = a[i].x;
        for(int j = val; j <= maxn; j++) {
            ans = (ans + f[i][j][1]) % mod;
        }
    }
    cout << ans << endl;
    return 0;
}
View Code

 


[ABC217G] Groups

题面翻译

对于$\forall k \in [1,n]$,求出把 [1,n] 中的 n 个整数分为非空的 k 组, 每组任意两个数模 m 不同余的方案数。

两个方案不同,当且仅当存在两个数,一种方案中它们在同一组, 但在另一种方案中,它们不同组。

对 998244353 取模。

$2 \le M \le N \le 5000$


 

$dp_{i, j}$ 维护前$\space i\space$个数,现在已经开了$\space j\space$组

那么开新的一组转移方程就是$\space dp_{i,j} \space =\space dp_{i-1, j-1}$

如果是加入原来开好的组,那么以$\space x\space$表示到$\space i\space$前有多少组已经被用了,那么转移方程就是$dp_{i,j}\space=\space dp_{i-1,j}\space \times \space x$

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;

const int N = 5005;
const int mod = 998244353;

//第 i 个数,当前有 j 组
ll f[N][N];

int main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n, m; cin >> n >> m;
    f[0][0] = 1;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= i; j++){
            //开一组新的
            f[i][j] = (f[i][j] + f[i - 1][j - 1]) % mod;
            //加到原来开出来的组中
            f[i][j] = (f[i][j] + f[i - 1][j] * max((ll)(j - (i - 1) / m), 0ll)) % mod;
        }
    }
    for(int i = 1; i <= n; i++) cout << f[n][i] << endl;
    return 0;
}
View Code

 


 

 

 

 

posted @ 2023-09-06 19:37  zhujio  阅读(68)  评论(0编辑  收藏  举报