1. 程式人生 > >每日一題之 hiho221 Push Button II (計數dp)

每日一題之 hiho221 Push Button II (計數dp)

描述 There are N buttons on the console. Each button needs to be pushed exactly once. Each time you may push several buttons simultaneously.

Assume there are 4 buttons. You can first push button 1 and button 3 at one time, then push button 2 and button 4 at one time. It can be represented as a string “13-24”. Other pushing way may be “1-2-4-3”, “23-14” or “1234”. Note that “23-41” is the same as “23-14”.

Given the number N your task is to find the number of different valid pushing ways.

輸入 An integer N. (1 <= N <= 1000)

輸出 Output the number of different pushing ways. The answer would be very large so you only need to output the answer modulo 1000000007.

樣例輸入 3 樣例輸出 13

思路:

統計方案數的題目可以用dp來做,不妨我們設dp[i][j]表示 數字 1~i 分成 j 組一共有多少種方案。那麼考慮 dp[i+1][j+1]等於多少? 在之前由於遞推求得了 dp[i][j] 了,那麼

  1. 一種情況是1~i 的數分成 j 組,然後第 i+1個數 獨立成為一組 ,相當於在分好的 j 組中 插空就行了,j 個組 一共 j+1 個空,所以這種情況的方案數是dp[i][j](j+1)dp[i][j]*(j+1)
  2. 另外一種情況是 1~i的數已經被分成了 j+1 個組,那麼第 i+1 這個數,隨便放到這 j+1中的任意一個組就行了,那麼這種情況的方案數是 d[i][j+1](j+1)d[i][j+1]*(j+1)

綜上就可以得出遞推式:dp[i][j]=dp[i1][j1]j+dp[i1][j]jdp[i][j] = dp[i-1][j-1]*j + dp[i-1][j]*j

#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

const int maxn = 1e3+5;
const int mod = 1e9+7;

typedef long long ll;

ll dp[maxn][maxn];

void solve(int n)
{
	memset(dp,0,sizeof(dp));
	for (int i = 1; i <= n; ++i)
		dp[i][1] = 1;

	for (int i = 2; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) {
			dp[i][j] = (dp[i-1][j-1]*j)%mod + (dp[i-1][j]*j)%mod;
			dp[i][j] %= mod;
		}
	}
	ll res = 0;
	for (int i = 1; i <= n; ++i) {
		res = (res + dp[n][i])%mod;
	}
	cout << res%mod << endl;
}

int main()
{

	int n;
	cin >> n;
	solve(n);

	return 0;
}