只写了和dp有关的。。博客 https://www.cnblogs.com/huyufeifei/p/10351068.html
关于状态的继承和转移
这题的状态转移要分开两步来做:
1.继承之前状态的合法构造数量
2.构造出该状态下特有的新构造数量
这类dp尽量由已知状态推出未知态(加法转移)来做。。。自己用减法转移都不知道边界怎么写。。
#include <cstdio> #include <algorithm> const int N = 510, MO = 998244353; int f[N][N][2], sum[N]; inline void add(int &a, const int &b) { a = (a + b) % MO; return; } int main() { int n, k; scanf("%d%d", &n, &k); for(int j = 1; j <= n; j++) { f[0][j][0] = 1; } for(int i = 0; i <= n; i++) { for(int j = 1; j <= n; j++) { // f[i][j][0/1]继承前状态 for(int k = 1; k < j && i + k <= n; k++) { add(f[i + k][j][0], f[i][j][0]); add(f[i + k][j][1], f[i][j][1]); } if(i + j <= n) {//构造出新的方案 add(f[i + j][j][1], f[i][j][0]); add(f[i + j][j][1], f[i][j][1]); } } } for(int i = 1; i <= n; i++)printf("%d ", f[n][i][1]); long long ans = 0LL; for(int i = 1; i <= n; i++) for(int j = 1; (long long)j * i < k && j <= n; j++) ans = (ans + f[n][i][1] * f[n][j][1] % MO) % MO; ans = ans * 2 % MO; printf("%lld ", ans); }
更新:可以把dp[i][j]转换成前缀和来做,最后相减一下就变成了上面的那种dp[i][j]表示的状态
相比上一中感觉更加直观好写,即对于每种状态,枚举k个连续的1放在末尾,然后把对应的之前的状态加上去就可以了
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; const int N = 505; const ll P = 998244353LL; int n, siz; ll f[N][N]; inline int min(int x, int y) { return x > y ? y : x; } int main() { scanf("%d%d", &n, &siz); f[0][0] = 1LL; for(int i = 1; i <= n; i++) for(int j = 1; j <= i; j++) for(int k = 1; k <= j; k++) f[i][j] = (f[i][j] + f[i - k][min(j, i - k)]) % P; for(int i = n; i >= 1; i--) f[n][i] = (f[n][i] - f[n][i - 1] % P + P) % P; //for(int i = 1; i <= n; i++)printf("%lld ", f[n][i]); ll ans = 0LL; for(int i = 1; i <= n; i++) for(int j = 1; j * i < siz && j <= n; j++) ans = (ans + f[n][i] * f[n][j] % P) % P; ans = ans * 2 % P; printf("%lld ", ans); }