计蒜客 NAIPC 2016 F. Mountain Scenes(dp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hxxjxw/article/details/82926895

题目大意:

       一条长为n,宽为1的丝带,可以剪成多条小丝带(长度须为整数)。将这些丝带分配到一个宽为w,高为h的矩形框内(每条丝带占宽度为1),丝带可以不全用上,但不能出现所有丝带长度都相等的情况(包括0)。并且不能将1条丝带叠放到另一条丝带的上方,就是每个宽度只能放一条丝带。现在给出n,w,h,求出有多少种不同的组合。

题解:
      一开始在往排列组合上想,推出如果n>=w*h,那么结果就是  (h+1)^{w}-(h+1)

然后n<w*h的情况,本想用隔板法  C_{n}^{0}+C_{n}^{1}+......+C_{n}^{w}-(\frac{n}{w}+1) ,但是这样的话就有可能某一段的长度大于h了......

后来看了dalao的博客才明白是dp......其实看到w,h的范围是100也多少有点dp的味道的

dp[i][j]代表前i个数,用的丝带总长度为j的方案数

\sum_{k=0}^{h}dp[i][j+k]+=dp[i-1][j] (j+k\leqslant n)

复杂度为O(nwh)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
#define mod 1000000007
using namespace std;
ll dp[110][10010];
int main()
{
    int n,w,h;
    cin>>n>>w>>h;
    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-1][j];//当前第i个位置应该放的丝带长度
                if(dp[i][j+k]>mod)
                    dp[i][j+k]-=mod;
            }
    ll ans=0;
    for(int i=0; i<=n; ++i)
    {
        ans+=dp[w][i];
        if(ans>mod)ans-=mod;
    }
    if(n<w*h)
        ans-=n/w+1;
    else ans-=h+1;
    ans=(ans+mod)%mod;
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hxxjxw/article/details/82926895