HDU 4477 HDOJ Cut the rope II

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

题目意思:

  给你一个长度为n的线段,要求至少分成两段,使得每段的长度各不相同。问分解的方案数。

首先考虑,若分解成k段,则n的值至少为1+2+3+4+...+k=(k+1)*k/2

所以本题k的最大值为315

考虑dp[k][n]表示长度为n的线段分解成k段的方案数。

其中分为两种情况

  k段均大于一,则将每段的长度减1后,与dp[k][n-k]的方案数相同。

  k段中有一段是1,则去掉这段长度为1的,有k-1段,且长度均大于一,与dp[k-1][n-k]方案数相同,这是k>2的情况。特殊的,k=2时,n=1,2无解为0,n>2方案为(1,n-1),即1。

代码:

 1 #include<cstdio>

 2 using namespace std;

 3 const int K=316,N=50000,m=1000000;

 4 int ans[N+10],s,dp[2][N+10];

 5 int main()

 6 {

 7     for(int i=3;i<=N;i++)

 8         ans[i]=dp[0][i]=dp[0][i-2]+1;

 9     for(int k=3;k<K;k++){

10         int *p1=dp[k&1],*p2=dp[(k+1)&1];

11         for(int i=k*(k+1)/2 - 1;i>0;i--)p1[i]=0;

12         for(int i=k*(k+1)/2;i<=N;i++){

13             p1[i]=p1[i-k]+p2[i-k];

14             if(p1[i]>=m) p1[i]-=m;

15             ans[i]+=p1[i];

16             if(ans[i]>=m) ans[i]-=m;

17         }

18     }

19     int T,n;

20     scanf("%d",&T);

21     while(T--){

22         //scanf("%d",&n);

23         printf("%d %d\n",T,ans[T]);

24     }

25     return 0;

26 }

 

你可能感兴趣的:(HDU)