题目描述
题目思路
在最多数据的情况下,有100个店100朵花,总情况为的天文数字,暴力枚举已经不可能实现,考虑使用动态规划解决问题。最后遇到的一定是花,所以思路更倾向于倒推。
建立二维数组,容易联想到为经过的花数,为经过的店数,的值代表此时酒量。但是这样 , 不能确定唯一的。且酒壶中的酒量最大可能达到数量级,如何储存这个大数据也是问题。
再关注数学问题本身。设第次遇到店添加的酒量为,易得:
根据题意,壶中酒量最大也不会超过100斗,极大简化了数据量。
此外由数据范围可以得到M<=2或N-M>7时无解,可以拿到极端测试点的分数。
在设计状态困难的情况下先找递推关系,写几组排列组合可以得到:
设为个店朵花的排列组合总数,则
这样可以得到有关店数和花数的状态转移方程,然而这道题还与壶中酒量这一额外变量有关,因此考虑用三维数组存储数据。设计三维数组,的值代表为经过个店,朵花时壶中的酒量为的方案数。初始状态显然为:
实际上后两个式子都能被递推出来,是多余的。接下来建立状态转移方程:
第二个式子省略了最后遇到的是店的情况,因为此时酒量为奇数,不可能遇到店。但是用上面的状态转移方程可能会出现或为负值的情况,因此完整的状态转移方程如下:
最终剩下的是一朵花和一斗酒。因此我们递推完成后,只需查看的值,即可获取答案。
我的代码
#include <iostream>
#include <algorithm>
using namespace std;
int dp[101][101][101];
int main() {
int n;
int m;
cin >> n >> m;
//设置初始状态
int i;
int j;
int k;
for (i = 0; i < 101; i++)
{
if (i == 2) {
dp[0][0][i] = 1;
}
else {
dp[0][0][i] = 0;
}
}
//动态规划
for (i = 0; i <= n; i++)
{
for (j = 0; j <= m; j++)
{
for ( k = 0; k <= 100; k++)
{
//分类讨论
if (k % 2 == 0 && i >= 1 && j >= 1) {
dp[i][j][k] = (dp[i - 1][j][k / 2] + dp[i][j - 1][k + 1])% 1000000007;
}
else if ((k % 2 != 0 || i <= 1) && j >= 1) {
dp[i][j][k] = (dp[i][j - 1][k + 1]) % 1000000007;
}
else if (k % 2 == 0 && j <= 1 && i >= 1) {
dp[i][j][k] = (dp[i - 1][j][k / 2]) % 1000000007;
}
}
}
}
//获取答案
int ans = dp[n][m - 1][1];
cout << ans;
return 0;
}
记得数据可能过大,每次运算都要取模。