CodeForces - 431C k-Tree(dp)

題目鏈接:點擊查看

題目大意:給出一棵無窮大的有根樹,每個節點都有 k 個兒子,每條邊都有權值,分別是 1 ~ k,現在問從根節點向下走,有多少條路徑的權值和等於 n ,且至少存在一條邊權大於等於 d 的邊

題目分析:讀完題感覺像揹包問題,花了一個小時想了個三維 dp,四層 for 用來轉移,正確性肯定是沒問題的,只不過有點太畫蛇添足了:

dp[ i ][ j ][ k ]:到了第 i 層,容量爲 j ,最大值爲 k 時的方案數,轉移的話一層枚舉層數,一層枚舉下一個數字,一層枚舉容量,一層枚舉最大值,非常囉嗦

訓練完看了看別人寫的題解,發現自己真的好菜啊好菜啊好菜啊好菜啊好菜啊

dp[ i ][ 0/1 ] 代表容量爲 i 時,是否含有大於等於 d 的邊權的方案數,轉移的話一層循環枚舉當前的容量,一層循環枚舉最後一次的數字用來轉移即可

本來以爲 dp 已經入門,足以應付這種簡單 dp,然鵝還是太菜了啊

代碼:
n^2

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
 
typedef long long LL;
 
typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=110;

const int mod=1e9+7;

LL dp[N][N];//dp[i][j]:總和爲i,是否包含大於等於d的數的方案數 

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.ans.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n,k,d;
	scanf("%d%d%d",&n,&k,&d);
	dp[0][0]=1;
	for(int i=1;i<=n;i++)//枚舉當前的容量 
		for(int j=1;j<=k&&j<=i;j++)//枚舉最後一次的數字 
		{
			if(j>=d)
				dp[i][1]=(dp[i][1]+dp[i-j][0]+dp[i-j][1])%mod;
			else
			{
				dp[i][1]=(dp[i][1]+dp[i-j][1])%mod;
				dp[i][0]=(dp[i][0]+dp[i-j][0])%mod;
			}
		}
	printf("%lld\n",dp[n][1]);









    return 0;
}

n^4

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
 
typedef long long LL;
 
typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=110;

const int mod=1e9+7;

LL dp[N][N][N];//dp[i][j][k]:到了第i個數字,容量爲j,最大值爲k時的方案數 

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.ans.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n,k,d;
	scanf("%d%d%d",&n,&k,&d);
	dp[0][0][0]=1;
	for(int s=1;s<=n;s++)//枚舉回合 
		for(int i=1;i<=k;i++)//枚舉數字 
			for(int j=i;j<=n;j++)//枚舉容量
				for(int t=0;t<=k;t++)//枚舉最大值 
					dp[s][j][max(t,i)]=(dp[s][j][max(t,i)]+dp[s-1][j-i][t])%mod;
	LL ans=0;
	for(int i=1;i<=n;i++)
		for(int j=d;j<=k;j++)
			ans=(ans+dp[i][n][j])%mod;
	printf("%lld\n",ans);









    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章