P6394 樱花,还有你 题解

· · 题解

P6394 题解

前言

题意

分析

状态及转移的设计

上代码!

#include <bits/stdc++.h>
#define N 5003
#define mod 10086001
using namespace std;
int n, m, s[N], f[N][N], pre[N][N], ans;

inline void read(int &x) {
    char ch = x = 0;
    while (ch < '0' || ch > '9') {
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + ch - 48;
        ch = getchar();
    }
    return ;
}

int main() {
    read(m), read(n);
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        read(s[i]);
        sum += s[i];
    }
    if (sum < m) { //判断 IMP
        printf("impossible");
        return 0;
    }
    f[0][0] = 1; //初始状态 
    for (int i = 0; i <= m; i++) { //注意要提前赋值 
        pre[0][i] = 1;
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= m; j++) {
            int minn = max(j - s[i], 0);
            f[i][j] = pre[i - 1][j];
            if (minn) f[i][j] -= pre[i - 1][minn - 1]; //计算转移 
            while (f[i][j] < 0) f[i][j] += mod; //解决出现负数的情况 
            pre[i][j] = f[i][j];
            if (j) pre[i][j] = (pre[i][j] + pre[i][j - 1]) % mod;
        }
    }
    for (int i = 1; i <= n; i++) { //统计答案 
        ans = (ans + f[i][m]) % mod;
    }
    printf("%d", ans);
    return 0;
}

空间优化

AC code

#include <bits/stdc++.h>
#define N 5003
#define mod 10086001
using namespace std;
int n, m, s[N], f[N], pre[N], ans;

inline void read(int &x) {
    char ch = x = 0;
    while (ch < '0' || ch > '9') {
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + ch - 48;
        ch = getchar();
    }
    return ;
}

int main() {
    read(m), read(n);
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        read(s[i]);
        sum += s[i];
    }
    if (sum < m) { //判断 IMP
        printf("impossible");
        return 0;
    }
    f[0] = 1;
    for (int i = 0; i <= m; i++) {
        pre[i] = 1;
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= m; j++) {
            int minn = max(j - s[i], 0);
            f[j] = pre[j];
            if (minn) f[j] -= pre[minn - 1];
            while (f[j] < 0) f[j] += mod; //计算转移并判负 
        }
        pre[0] = f[0];
        for (int j = 1; j <= m; j++) {
            pre[j] = (f[j] + pre[j - 1]) % mod; //先计算 f 后计算 pre
        }
        ans = (ans + f[m]) % mod; //直接统计答案 
    }
    printf("%d", ans);
    return 0;
}