http://acm.hdu.edu.cn/showproblem.php?pid=4377
写了一下午也没找出规律 还剩十几分钟的时候CZ看出了规律 这时候再找正确的字典序已经晚了,,
官方解题报告:
其实这是个挺有趣的题,你需要构造一个 1..N 的排列,使得其最长上升序列的长度和最长下降序列的长度的最大值最小。应该比较容易能够想到这个答案是 sqrt(N) 级别的,这个结论的证明可以参考吴文虎的那本组合数学 p21 。
当
然这还没有结束,怎么找字典序最小的那个解呢?先看看完全平方数吧,对于 4 ,我们有 2 1 4 3 ,对于 9 ,我们有 3 2 1 6 5 4
9 8 7 。嗯,完全平方数的规律还是好找的,那么 5 呢?不就是加一个数么,1 3 2 5 4
,如果你觉得这是答案,那你就大错特错了,答案是 1 2 5 4 3 。同样,对于 10 ,答案是 1 2 6 5 4 3 10 9 8 7 。
于是我们就可以构造程序,每次以 ceil(sqrt(N)) 为一组,尽量把大的数安排到后面的组中,同时要注意,一定要分出 ceil(sqrt(N)) 组,能让较小的 1 2 这样的数能够排在前面。
最后,这题并不难,但是做到 1Y 也不容易,这就要克服各种逻辑上的问题,形成良好的思维习惯,对于解题来说也是十分重要的。
把这N个数放在sqrt(N)块中 要保证大数尽量在后面 比如分成5块 就尽量让最后几块都填满 在保证前几块至少有一个的情况下
10 1 ,2, 6 5 4 3, 10 9 8 7,
11 1, 3 2, 7 6 5 4, 11 10 9 8,
12 1, 4 3 2, 8 7 6 5, 12 11 10 9.
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include<math.h> 5 int num[10001]; 6 int main() 7 { 8 int t,a,i,j,k,y,d,kk,yy; 9 scanf("%d",&t); 10 while(t--) 11 { 12 d = 0; 13 kk = 0; 14 scanf("%d",&a); 15 int x = sqrt(a); 16 if(x*x==a) 17 k = x; 18 else 19 k = x+1; 20 d = k; 21 while(a)//求每个区域放几个数 22 { 23 if(a-(d-1)>=k) 24 { 25 num[d--] = k; 26 a-=k; 27 } 28 else 29 if(a>d) 30 { 31 num[d] = a-d+1; 32 int dd = a-d+1; 33 d--; 34 a-= dd; 35 } 36 else 37 { 38 num[d--] = 1; 39 a--; 40 } 41 } 42 y = 0; 43 for(i =1 ; i <= k ; i++) 44 { 45 y+=num[i]; 46 yy = y; 47 for(j = num[i] ; j >= 1 ; j--) 48 { 49 if(kk!=0) 50 printf(" "); 51 printf("%d",y); 52 y--; 53 kk++; 54 } 55 y = yy; 56 } 57 printf("\n"); 58 } 59 return 0; 60 }