dp好弱鸭。。
这个题目关键在于递推方程,这个递推方程怎么得到的呢?
dp[i][j]代表第行,放j个绸缎可以放的的方法数,三个for循环分别控制,第一个for控制在前i列放绸缎,j控制在这前i列放单位绸缎的个数,放绸缎的个数不超过长*宽,所以用当j+k>n break。k控制在一列中放绸缎的数量,放绸缎的数量不超k个。
再分析一下dp方程,dp[i][j+k]=dp[i][j+k]+dp[i-1][j],用一个样例分析,dp2,3就是在前2列放3个单位的绸缎有多少种方法,dp2,3=dp1,0+dp1,1+dp1,2+dp1,3为什么等于这四个数的和呢?其实分别就是在第一列放0个第二列放3个、第一列放1个第二列放2个,第一列放2个第二列放0个,第一列放0个第二列放3个的这四种方法数之和。
这个题目还有一点就是对于一个被减数的取模,因为被减数可能为负,所以把被减数加上mod后加成正的以后再取模。
#include<iostream>
#include<cstring>
#define mod 1000000007
typedef long long ll;
using namespace std;
ll dp[110][10010];
int main(){
ll n,w,h;
cin>>n>>w>>h;
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=w;i++){
for(int j=0;j<=n;j++){
for(int k=0;k<=h;k++){
if(j+k>n)break;
dp[i][j+k]=dp[i][j+k]+dp[i-1][j];
if(dp[i][j+k]>mod)
dp[i][j+k]-=mod;
}
}
}
// for(ll i=1;i<=w;i++){
// for(ll j=1;j<=n;j++)
// cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
// }
ll sum=0;
for(int i=0;i<=n;i++){
sum+=dp[w][i];
if(sum>mod)
sum-=mod;
}
// sum-=n/w+1;
if(n>w*h)
sum-=h+1;
else
sum-=n/w+1;
while(sum<=0){
sum+=mod;
}sum%=mod;
cout<<sum<<endl;
}