1. 程式人生 > >計蒜客 NAIPC 2016 F. Mountain Scenes(dp)

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

題目大意:

       一條長為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;
}