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 }