1. 程式人生 > >「專題訓練」k-Tree(CodeForces Round #247 Div.2 C)

「專題訓練」k-Tree(CodeForces Round #247 Div.2 C)

cout code names spa 題意 某個結點 增長 space force

題意與分析(Codeforces-431C)

題意是這樣的:給出K-Tree——一個無限增長的樹,它的每個結點都恰有\(K\)個孩子,每個節點到它\(K\)個孩子的\(K\)條邊的權重各為\(1,2,...,K\),問現有多少條路徑,使從根節點出發到某個結點所經過的邊權重之和恰為n,且經過的邊至少有一條權重不小於\(d\)
我們來考慮一下階段:一層一層的走下去——這個是顯然的。而狀態是什麽?影響我們答案(路徑條數)的只有一個,權重的和,它是由我們底下的若幹個孩子所走的權重和的情況的和構成的。從某個節點走到某個節點改變了什麽?當我走了一條邊i,我就還剩\(n-i\)的權重需要走了。而我有\(k\)

個邊,因此對於一個K-Tree的某個點(每個點是等價的,所以決定性因素只能是和),如果它還剩\(n\)的權重和沒有走,那麽它的狀態轉移方程就是\(dp[n-1]+dp[n-2]+...+dp[n-k]=dp[n]\)。這樣就能求出沒有限制條件下的路徑個數。
然後考慮一下限制條件。不小於\(d\),很自然地會覺得有點困難去實現。於是想到正難則反,我們求出所有邊權重小於d的情況就行了——也就是\(k=d-1\)。而同樣的,不改變的是預先的權重和\(n\),因此再次運用上面的狀態轉移方程,然後把\(k\)代入為\(d-1\)即可。二者最後相減即可。

代碼

註意減法操作時候的取模。

#include <bits/stdc++.h>
using namespace std;

const long long mod=1e9+7;
long long dpa[105], dpb[105];
int main()
{
    int n,k,d; cin>>n>>k>>d;
    dpa[0]=dpb[0]=1;
    for(int i=1;i<=n;++i)
    {
        for(int j=1; j<=k && i-j>=0; ++j)
        {
            dpa[i]=(dpa[i]+dpa[i-j])%mod;
        }
    }
    for(int i=1;i<=n;++i)
    {
        for(int j=1; j<=d-1 && i-j>=0; ++j)
        {
            dpb[i]=(dpb[i]+dpb[i-j])%mod;
        }
    }
    cout<<(dpa[n]-dpb[n]+mod)%mod<<endl;
    return 0;
}

「專題訓練」k-Tree(CodeForces Round #247 Div.2 C)