【Gym

Mountain Scenes

Descriptions

给你一个长度为n的丝带,一个宽w一个高h 的 格子,用丝带去填充格子,这填充后只需要满足至少有一列的丝带长度与其他格子不同即可。丝带可以不全部用上,格子可以不放丝带,只要有一列的丝带长度不同则这种放法就与其他方案不同。问一共有多少种放放法。

Sample Input1 

 25 5 5 

Sample Output 1

7770

Sample Input 2

15 5 5

Sample Output 2

 6050

Sample Input 3

10 10 1

Sample Output 3

 1022

Sample Input 4

4 2 2 

Sample Output 4

6

题目链接

https://vjudge.net/problem/Gym-101002F

dp[i][j]代表到第i列为止用了j米长的情况数,下一状态等于前一状态的各种情况的总和

代码中有几点要解释一下   tmp=n/w+1 求的是按宽绳子全用铺平,看能铺几层 再加上 0这一层

            h+1 求的是按高来铺绳子,能铺h+1层

            min(tmp,h+1) 求的是最终能铺几层

AC代码

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define Mod 1000000007
#define eps 1e-6
#define ll long long
#define INF 0x3f3f3f3f
#define MEM(x,y) memset(x,y,sizeof(x))
#define Maxn 10000+10
using namespace std;
ll n,w,h;
ll dp[110][Maxn];
int main()
{
    cin>>n>>w>>h;
    MEM(dp,0);
    dp[0][0]=1;
    for(int i=1; i<=w; i++)//枚举列
        for(int j=0; j<=n; j++)//枚举到前一列为止用了多少绳子
            if(dp[i-1][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])%Mod;
                }
            }
    ll tmp=n/w+1;
    ll ans=0;
    for(int i=0;i<=n;i++)
        ans=(ans+dp[w][i])%Mod;
    cout<<(ans-min(tmp,h+1)+Mod)%Mod<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/sky-stars/p/11232788.html