简单游戏
题目大意
原本有n个数字,第1,2个相加,第2,3个相加……第n-1,n个相加,由此得出一个长度为n-1的新序列,然后不停重复,最后得出一个t,现在给出一开始的n和t求符合的序列(字典序 最小)(多组数据,0 0结束)
样例输入
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
数据范围限制
数据保证有解。请注意加粗字体!
对于30%的数据,保证该组里的每个N都不超过10。
对于100%的数据,保证有每个N不超过20,且每组数据的个数不超过10。
解题思路
我们可以由题意得出下图,图中代表的是数字相加的次数,可以看出,这是一个杨辉三角,我们可以先求出杨辉三角,再dfs枚举每一个数
三个优化(必打):
1:判断当前总值是否大于t,若大于,退出
2:因为杨辉三角有对称的特性,所以判断a[i]是否大于a[n-i+1],若不大于,退出
3:将剩下的数和杨辉三角剩下可乘的的数排列,将最大的乘最大的,最小的成最小的,得出剩下的数最大的结果,若当前总值+最大的结果<t 那么绝对不可能有结果,就退出,然后将最大的乘最小的,最小的乘最大的,得出最小的结果,若当前总值+最小的结果>t 那么绝对不可能有结果,就退出
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int c[ 25 ] , yh[ 25 ] [ 25 ] , p[ 25 ] , s[ 25 ] , h[ 25 ] , n, t, dg;
void dfs ( int x, int y)
{ if ( x> n&& y== t) { dg= 1 ; return ; } if ( x> n) return ; if ( y>= t) return ; int w= 0 , big= 0 , small= 0 ; for ( register int i= 1 ; i<= n; i++ ) if ( ! p[ i] ) { s[ ++ w] = i; h[ w] = yh[ n] [ x+ w- 1 ] ; } sort ( h+ 1 , h+ 1 + w) ; for ( register int i= 1 , j= w; i<= w; i++ , j-- ) { small+ = s[ i] * h[ j] ; big+ = s[ i] * h[ i] ; } if ( y+ big< t) return ; if ( y+ small> t) return ; for ( register int i= 1 ; i<= n; i++ ) if ( ! p[ i] ) { if ( x> n/ 2 && i<= c[ n- x+ 1 ] ) continue ; c[ x] = i; p[ i] = 1 ; dfs ( x+ 1 , i* yh[ n] [ x] + y) ; p[ i] = 0 ; if ( dg) return ; c[ x] = 0 ; }
}
int main ( )
{ yh[ 1 ] [ 1 ] = 1 ; for ( register int i= 2 ; i<= 20 ; i++ ) for ( register int j= 1 ; j<= i; j++ ) yh[ i] [ j] = yh[ i- 1 ] [ j- 1 ] + yh[ i- 1 ] [ j] ; scanf ( "%d %d" , & n, & t) ; while ( n|| t) { dg= 0 ; memset ( c, 0 , sizeof ( c) ) ; dfs ( 1 , 0 ) ; for ( int i= 1 ; i<= n; i++ ) printf ( "%d " , c[ i] ) ; printf ( "\n" ) ; scanf ( "%d %d" , & n, & t) ; } return 0 ;
}