DP, 最优解这里变成了遍历所有可能组合的总数(和一般的有点小不一样)

#include <stdio.h> 


 unsigned long UnimodalNum[1000][1000] = {0}; 


 void init() { 

     for(int i = 0; i <1000; i++) { 

         for (int j = 999; j >= 0; j--) { 

             if (i == 0) { // N is 0. 

                 UnimodalNum[i][j] = 1;    // N is 0, means no change any more, so only 1 combination. 

             } else if (j == 0) { // start from 0. 

                 UnimodalNum[i][j] = -1; 

             } else if (i < j) { 

                 UnimodalNum[i][j] = -1; 

             } else if (i == j) { 

                 UnimodalNum[i][j] = 1; 

             } else { 

                 UnimodalNum[i][j] = -1; 


                 long uniNum = 0; 

                 long begin = j-1; 

                 while (1) { 

                     // printf("%d\n", begin); 

                     begin++; 

                     if (begin >= (i/2 + 1)) { 

                         break; 

                     } else if (begin*2 == i) { 

                         uniNum += 1; 

                     } else if (i - begin*2 < begin) { 

                         continue; 

                     } else { 

                         if (UnimodalNum[i - 2*begin][begin] == -1) { 

                             uniNum += 1; 

                         } else { 

                             uniNum += UnimodalNum[i - 2*begin][begin]; 

                         } 

                     } 

                 } 

                 UnimodalNum[i][j] = uniNum + 1; 

             } 

         } 

     } 

 } 


 int main() { 

     int num; 

     init(); 

     while(1) { 

         scanf("%d", &num); 

         if (num == 0) { 

             return 0; 

         } 

         printf("%d %lu\n", num, UnimodalNum[num][1]); 

     } 

 }

题最大的输入 是 231,

所以维护一个232的二维矩阵就够了。

还有一点就是 全部用long(包括中间数据), 不然220以后就溢出了。

着了的 unimodlNum[i][j]的含义是:

总数N为i, 从j开始进行回文不递减排列的组合的个数。

极限情况:

i == 0, 没有意义, 设为 -1.

i == j, 只有一种排列方式.

i < j, 这种情况根本没有排列, 无解, 设 -1;。

j == 0, 也没啥意义, 设为 -1;

一般情况:

从j开始遍历(设遍历变量为begin),在(j每次递增)

当j == 2*i时,组合个数+1           (i, i)

当  j >= i/2+1时,后面已经不再可能有解, 跳出循环.

当 j - 2i < i时, 此组合不是解,但是不能跳出循环, 继续后面(后面还可能有解, 这种情况下不可能在有 (j, ....., j)的组合, 但还可能有(j,j)的组合)

其他的 则是 组合个数 +  unimodlNum[i - 2*begin][begin],

再分为: 如果 unimodlNum[i - 2*begin][begin],是一个无效解, 那么组合个数加1(及 (j....j)的组合不可能存在, 但是可以由(j,i-2j,j)的组合)

     否则 组合个数+unimodlNum[i - 2*begin][begin]。


这些题深感 主要难处是要去想清楚所有的边边角角.