【HDU4301】Divide Chocolate

题意

  有一块n*2的巧克力,将它分成k块,问有多少种方法。

分析

  emmm是dp没错了。

  最容易想到的状态定义是f[i][j],意思是前i行,分成j块的方案数。但是发现没法转移。(后面会说一下为什么···)

   我们把状态定义为f[i][j][0]和f[i][j][1]。

   f[i][j][0]:前i行分成j块,且第i行的两小块巧克力是没有连在一起的。

   f[i][j][1]:前i行分成j块,且第i行的两小块巧克力是连在一起的。

   我们来把转移分一下类。

   情况1:从i行到i+1行的时候,巧克力的块数多了两块。这说明,第i+1行的两小块一定是分开的,而且没有和第i行的相连。那么转移只有一种情况f[i][j][0]=f[i-1][j-2][0]+f[i-1][j-2][1]

   情况2:从i行到i+1行的时候,巧克力的块数多了一块。如果第i+1行的两小块是连在一起的一整块,那么一定没有和i行的相连。既f[i][j][1]=f[i-1][j-1][0]+f[i-1][j-1][1]。如果第i+1行的两小块是分开的,那么一定有一块是和i行相连。既f[i][j][0]=f[i-1][j-1][1]*2+f[i-1][j-1][0]*2

   情况3:从i行到i+1行的时候,巧克力的块数没有增加。这就说明第i+1行的一定是和i行相连的。如果第i+1行两小块是分开的,那么第i行一定是分开的。所以f[i][j][0]=f[i-1][j][0]。如果i+1行两小块是和在一起的,那么就要分类讨论。

 思路大概就是这个样子。。。

  至于为什么简单的定义为f[i][j]没法转移,因为,我试过了···他就是没法转移···········

  咳咳不闹,我们来看第三种情况,他的转移是和前一行是分开还是连在一起的有关。所以我们要表示出这个状态。

  下面是代码,我尽量写的可读性强一些了···

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 const int maxn=1000+100;
 8 const int MOD=100000007;
 9 int n,k,T;
10 int f[maxn][2*maxn][3];//0分开,1和起来
11 int main(){
12     scanf("%d",&T);
13     for(int t=1;t<=T;t++){
14         memset(f,0,sizeof(f));
15         scanf("%d%d",&n,&k);
16         f[1][1][1]=f[1][2][0]=1;
17         for(int i=2;i<=n;i++){
18             f[i][2*i][0]=1;f[i][1][1]=1;
19             for(int j=2;j<2*i;j++){
20                 //******第1,2种情况***********
21                 f[i][j][1]=(f[i-1][j-1][1]+f[i-1][j-1][0])%MOD;//1.1
22                 f[i][j][0]=(f[i-1][j-1][1]*2+f[i-1][j-1][0]*2)%MOD;//2.1
23                 f[i][j][0]=(f[i][j][0]+f[i-1][j-2][1]+f[i-1][j-2][0])%MOD;//2.2
24 
25                 //*********第3种情况**************
26                 f[i][j][1]=(f[i][j][1]+f[i-1][j][0]*2+f[i-1][j][1])%MOD;
27                 f[i][j][0]=(f[i][j][0]+f[i-1][j][0])%MOD;
28             }
29         }
30         int ans=(f[n][k][0]+f[n][k][1])%MOD;
31         printf("%d
",ans);
32     }
33 return 0;
34 }
View Code
原文地址:https://www.cnblogs.com/LQLlulu/p/8971917.html