【usaco】Bessie's Secret Pasture 贝茜的秘密草坪
Bessie's Secret Pasture 贝茜的秘密草坪
这道题dp的转移的方式很妙,值得一记。
说实话,拿到这道题,我先想到的是一个5维的转移方程,不详细说,大概可以理解为我记录了各个重复物品的情况吧,毕竟最终方案是要考虑顺序的;我的目的是先跑多重背包,然后在答案处最后求组合数,然而实现太麻烦。
看了题解,我才感慨。
让我们直接看看状态枚举吧:
这是我们熟知的 01背包 的写法:先枚举物品,再枚举体积
而在此基础上的 多重背包 的写法:先枚举物品,接着是枚举放置物品个数,最后枚举体积
另外还有 记录已放物品数量的01背包 的写法:先枚举物品,接着是已放置物品个数,最后枚举体积 (最后两个好像可以调换)
而这道题则做出了美妙的变化:先枚举体积,再已放置物品个数,再枚举体积。 实际上这种做法放宽了转移,有意维护了选取物品顺序的随机 。
#include <map> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <cstdio> #include <vector> #include <bitset> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define INF (0x3f3f3f3f) #define F(x, y, z) for(int x=y; x<=z; x++) #define D(x, y, z) for(int x=z; x>=y; x--) #define Mem(x, y) memset(x, (y), sizeof(x)) using namespace std; #define N (10000) #define L (500) int n, n2, dp[N+L][5]; int main () { cin >> n; n2=sqrt(n); dp[0][0]=1; F(i, 1, n) F(j, 1, 4) for(int k=0; k*k<=i; k++) dp[i][j]+=dp[i-k*k][j-1]; cout << dp[n][1]+dp[n][2]+dp[n][3]+dp[n][4]; return 0; }