混沌DM

DM Hunter

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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 }

 

posted on 2012-12-07 22:59  混沌DM  阅读(376)  评论(1编辑  收藏  举报