1. 程式人生 > 實用技巧 >hdu6787(骰子+往回推的傳輸帶問通過方案,dp)

hdu6787(骰子+往回推的傳輸帶問通過方案,dp)

題:http://acm.hdu.edu.cn/showproblem.php?pid=6787

題意:有1~n標號的格子,上面有m個傳輸帶(傳送帶傳的位置要傳到之前去,1位置不能有格子)1~11的骰子,問有多少種安傳輸帶的方案使得仍有可能從1到n(到n不動),期間位置不能超過n

分析:可以發現,只要不要連續安傳輸帶的個數不大於10,則有可能從1到n,決策就是要不要在當前位置安傳輸帶;

   設dp[i][j][k],表示在位置 i 用了 j 個傳輸帶從i開始連續有k個傳輸帶的方案數,那麼dp[i][j][k]就是由dp[i-1][j-1][k-1]*(i-1)得來的,其中*(i-1)代表在位置 i 裝傳輸帶可以傳到的範圍為[1,n-1] ,n-1種可能;

   k最多為10,在dp過程種累加即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=1e3+3;
const int mod=1e9+7;
int dp[M][M][13];
void init(){
    dp[2][0][0]=1;
    for(int i=2;i<=1000;i++)
        for(int j=0;j<=1000;j++)
            for(int k=0;k<=10;k++){
                dp[i
+1][j+1][k+1]=(dp[i+1][j+1][k+1]+1ll*(i-1)*dp[i][j][k])%mod; dp[i+1][j][0]=(dp[i+1][j][0]+dp[i][j][k])%mod; } } int main(){ init(); int T; scanf("%d",&T); while(T--){ int n,m; scanf("%d%d",&n,&m); if(m>max(0,n-2)){puts("
-1");} else if(n<3){ puts("1"); } else printf("%d\n",dp[n+1][m][0]==0?-1:dp[n+1][m][0]); } return 0; }
View Code