如果给出一个由1~n组成的序列,我们可以每相邻2个数求和,得到一个新的序列,不断重复,最后得到一个数sum,
现在输入n,sum,要求输出一个这样的排列,如果有多种情况,输出字典序最小的那一个。
刚开始我是直接搜,tle了
然后就开始找最初的序列和最终的和有什么关系
因为最终的和sum一定是等于若干个a[1],若干个a[2],...,若干个a[n]的和
即sum=p1*a1+p2*a2+...+pn*an
所以我们只要求出数组a的系数,n个p即可。
然后发现,和杨辉三角有很大的关系。
如果杨辉三角的行数从1开始算的话,
对于某一个1~n的排列得到sum,就需要有n个系数p,发现,这n个系数就刚好是杨辉三角的第n行。
所以对于等式:sum=p1*a1+p2*a2+...+pn*an
知道了n,我们就知道了n个系数p了,sum也知道
所以只要枚举1~n的排列,刚哪一个排列符合等式就ok了
又要字典序顺序,所以我们从小到大的顺序枚举,一有答案了,就跳出来。
1 #include<cstdio> 2 #include<cstring> 3 4 using namespace std; 5 6 const int maxn=13; 7 int c[maxn][maxn]; 8 int a[maxn]; 9 int n,sum; 10 bool flag; 11 12 void init_c() 13 { 14 memset(c,0,sizeof c); 15 for(int i=1;i<maxn;i++) 16 { 17 c[i][1]=1; 18 for(int j=2;j<=i;j++) 19 c[i][j]=c[i-1][j-1]+c[i-1][j]; 20 } 21 } 22 23 void solve() 24 { 25 int ret=0; 26 for(int i=1;i<=n;i++) 27 { 28 ret+=c[n][i]*a[i]; 29 } 30 if(ret==sum) 31 { 32 flag=true; 33 for(int i=1;i<n;i++) 34 printf("%d ",a[i]); 35 printf("%d ",a[n]); 36 } 37 return ; 38 } 39 40 void next(int cur) 41 { 42 if(flag) 43 return ; 44 if(cur==n+1) 45 { 46 solve(); 47 return ; 48 } 49 for(int i=1;i<=n;i++) 50 { 51 int ok=1; 52 for(int j=1;j<cur;j++) 53 { 54 if(a[j]==i) 55 ok=0; 56 } 57 if(ok) 58 { 59 a[cur]=i; 60 next(cur+1); 61 } 62 } 63 64 } 65 66 int main() 67 { 68 init_c(); 69 while(~scanf("%d%d",&n,&sum)) 70 { 71 flag=false; 72 next(1); 73 } 74 return 0; 75 }