题目大意:就是农夫和这只牛又杠上了(怎么老是牛啊,能换点花样吗),给出一行数(从1到N),按杨辉三角的形式叠加到最后,可以得到一个数,现在反过来问你,如果我给你这个数,你找出一开始的序列(可能存在多个序列,输出字典序最小的那个)。
这一题首先你要看懂原文的那个1到N是什么意思,就是那一行数只能是1到N,而不是1到10(我一开始犯了这个愚蠢的错误,导致枚举到风扇呼呼的转),如果是这样给你,那么这道题就很简单啦,就直接是用next_permutation枚举所有的序列就可以了,然后找出字典序最小的那个。
但是这里有个问题,如果你真的找出一个然后去比较字典序,那真是太慢了,一开始直接暴力枚举+测试一个一个字串的速度
看到了没?差点就超时了,这个还是我直接用二维数组+迭代的,换暴力DFS直接就超时了吧。
其实这个时候我们可以看到,这样做我们忽略了一个事实,如果字串是顺序的,我们可以回想一下我们的枚举是怎枚举的(STL里面也是这么写的),是一个循环从1到N,然后找到没有被标记的数,然后进去递归,这样的话,其实就隐含了字典序排序了,如果我们一开始按照12345678...这样排列下来,那么找到的第一个字串,肯定是字典序最小的,所以,我们找到之后直接break就可以了
1 #include <iostream> 2 #include <functional> 3 #include <algorithm> 4 5 using namespace std; 6 7 static int set[11], tmp[11]; 8 static int sum, length; 9 10 void enum_string(const int,const int); 11 bool scmop(void); 12 13 int main(void) 14 { 15 while (~scanf("%d%d", &length, &sum)) 16 { 17 for (int i = 1; i <= length; i++) 18 tmp[i - 1] = i; 19 if (length == 1 && tmp[0] == sum) 20 { 21 for (int i = 0; i < length; i++) 22 printf("%d ", tmp[i]); 23 printf(" "); 24 continue; 25 } 26 do{ 27 for (int i = 0; i < length - 1; i++) 28 set[i] = tmp[i] + tmp[i + 1]; 29 for (int i = length - 2; i >= 0; i--) 30 { 31 for (int j = 0; j < i; j++) 32 set[j] = set[j] + set[j + 1]; 33 } 34 if (set[0] == sum) 35 { 36 for (int i = 0; i < length; i++) 37 printf("%d ", tmp[i]); 38 printf(" "); 39 break; 40 } 41 } while (next_permutation(tmp, tmp + length)); 42 43 } 44 return 0; 45 }
还没完,开始我不是说了吗?这一题是按照杨辉三角的形式展开的,我们知道杨辉三角的每一行的数都是组合数Ckn,那么在数学上,杨辉三角的加法一行数的相加次数相当于这个Ckn,
也就是说,我们只用把这一行的数乘以Ckn就可以得到结果了,这样做会更快
1 #include <iostream> 2 #include <functional> 3 #include <algorithm> 4 5 using namespace std; 6 7 static int set_sum, tmp[11], Cn[11]; 8 static int sum, length; 9 10 void Cal_Cn(const int); 11 12 int main(void) 13 { 14 while (~scanf("%d%d", &length, &sum)) 15 { 16 for (int i = 1; i <= length; i++) 17 tmp[i - 1] = i; 18 memset(Cn, 0, sizeof(Cn)); 19 Cal_Cn(length); 20 if (length == 1 && tmp[0] == sum) 21 { 22 for (int i = 0; i < length; i++) 23 printf("%d ", tmp[i]); 24 printf(" "); 25 continue; 26 } 27 do{ 28 set_sum = 0; 29 for (int i = 0; i < length; i++) 30 set_sum += Cn[i] * tmp[i]; 31 if (set_sum == sum) 32 { 33 for (int i = 0; i < length; i++) 34 printf("%d ", tmp[i]); 35 printf(" "); 36 break; 37 } 38 } while (next_permutation(tmp, tmp + length)); 39 } 40 return 0; 41 } 42 43 void Cal_Cn(const int length) 44 { 45 Cn[0] = 1; 46 for (int j = 1; j < length; j++) 47 { 48 Cn[j] = length - 1; 49 for (int k = 2; k <= j; k++) 50 Cn[j] *= (length - k); 51 for (int k = 1; k <= j; k++) 52 Cn[j] /= k; 53 } 54 }
最后,32ms