题目 :
Charles和sunny在玩一个简单的游戏。若给出1~n的一个排列A,则将A1、A2相加,A2、A3相加……An-1、An相加,则得到一组n-1个元素的数列B;再将B1、B2相加,B2、B3相加,Bn-2、Bn-1相加,则得到一组n-2个元素的数列……如此往复,最终会得出一个数T。而Charles和sunny玩的游戏便是,Charles给出n和T,sunny在尽可能短的时间内,找到能通过上述操作得到T且字典序最小的1~n的排列。(sunny大声说:“What an easy game!”,接着几下就给出了解),Charles觉得没意思,就想和你玩,当然,你可以用一种叫做“电子计算机”的东西帮你。
输入:
本题有多组数据,对于每组数据:一行两个整数n(0<n<=20),t即最后求出来的数。两个0表示输入结束。
输出:
对于每组测试数据输出一行n个整数,用空格分开,行尾无多余空格,表示求出来的满足要求的1~n的一个排列。
样例输入:
4 16
3 9
0 0
样例输出:
3 1 2 4
1 3 2
对样例解释:
开始排列:3、1、2、4
第一次操作:3+1=4 1+2=3 2+4=6
得到:4、3、6第二次得到:7、9最后就是:16
分析:
题目要求1-N的一个排列A1,A2…An使得C(N-1,0)*A1+C(N-1,1)*A2+….+C(N-1,N-1)*AN=T-------1式,(有点像杨辉三角)
方法很好确定,先把C(N-1,i)求出来,然后只要把每一个位上的数确定好就可以了,所以采用深度优先搜索的方法。
方法:直接搜,用DFS(x,y)表示当前将要确定第x个位置上数,已经确定的和为y,把每种情况都搜出来,然后在递归出口的位置判断1式是否成立,不过很可惜,这种方法得不到分(超时);
剪枝一:加一个小小的优化,就是在确定第X个数时,保证新求出来的y不能大于T,加上这个优化后,可以得40分;
剪枝二:由于C(N-1,i)=C(N-1,N-1-i),具有对称性,题目又要求最小字典序列,所以在枚举时当x>n div 2 时,要保证a[x]>a[N+1-x],这样程序速度会提高,但是该题还是只能得40分;
剪枝三:当枚举到第X个数时,剩余的N-X个数,与剩余的N-X个系数一一对应,让大数和大系数相乘,小数和小系数相乘可以得到最大值,让大数和小系数相乘,小数和大系数相乘可以得到最小值,如果剩余的值不在这个范围内,就不要搜下去,这样可以大大优化,拿样例举例来说:
N=4,T=16。
当枚举a[1]=1时,剩余16-1*1=15,剩余的未放置的数为2,3,4,剩余的系数为1,3,3,这样最大值为4*3+3*3+2*1=23,最小值为4*1+3*3+2*3=19,都超过了15,所以第一个数不能选1。
其实就是dfs+一堆优化。恶心,还不能保证是否过。
code:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cmath> 6 #define N 55 7 using namespace std; 8 int f[N][N]; 9 int q[N],t[N],x[N]; 10 int n=1,m=1; 11 bool b; 12 bool cmp(int x,int y) { 13 return x>y; 14 } 15 void pre() { 16 memset(f,0,sizeof(f)); 17 f[1][1]=1; 18 for (int i=2; i<N; ++i) { 19 for (int j=1; j<=i; ++j) { 20 f[i][j]=f[i-1][j-1]+f[i-1][j]; 21 } 22 } 23 24 } 25 bool pd(int dep,int s) { 26 int an=s; 27 for (int i=dep; i<=n; ++i) { 28 x[i-dep]=f[n][i]; 29 } 30 sort(x,x+n-dep+1,cmp); 31 int j=0; 32 for (int i=n; i>=1; --i) { 33 if (t[i]==0) { 34 an+=i*x[j]; 35 j++; 36 } 37 } 38 if (an<m) { 39 return true; 40 } 41 an=s; 42 j=0; 43 for (int i=1; i<=n; ++i) { 44 if (t[i]==0) { 45 an+=i*x[j]; 46 j++; 47 } 48 } 49 50 if (an>m) { 51 return true; 52 } 53 return false; 54 } 55 void dfs(int dep,int s) { 56 if (b==1) return; 57 if (dep==n) { 58 if (s==m) { 59 for (int i=1; i<=n; ++i) { 60 printf("%d ",q[i]); 61 } 62 printf("\n"); 63 b=1; 64 } 65 return; 66 } 67 if (s>m) { 68 return; 69 } 70 if (pd(dep+1,s)) { 71 return; 72 } 73 if (dep>n/2 && q[dep]<q[n-dep+1]) { 74 return; 75 } 76 for (int i=1; i<=n; ++i) { 77 if (t[i]==0) { 78 t[i]=1; 79 q[dep+1]=i; 80 dfs(dep+1,s+i*f[n][dep+1]); 81 t[i]=0; 82 } 83 } 84 } 85 int main() { 86 //freopen("easy.in","r",stdin); 87 //freopen("easy.out","w",stdout); 88 while(n&&m) { 89 scanf("%d%d",&n,&m); 90 pre(); 91 b=0; 92 memset(t,0,sizeof(t)); 93 dfs(0,0); 94 } 95 return 0; 96 }
这种题优化不能保证过,但你也没有办法。
这道题也是看了题解才过的。