洛谷1118 数字三角形游戏
题目描述
有这么一个游戏:
写出一个1~N的排列a[i],然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少1,直到只剩下一个数字位置。下面是一个例子:
3
1 2 4
4
3 6
7
9
16
最后得到16这样一个数字。
现在想要倒着玩这样一个游戏,如果知道N,知道最后得到的数字的大小sum,请你求出最初序列a[i],为1~N的一个排列。若答案有多种可能,则输出字典序最小的那一个。
输入输出格式
输入格式:
两个正整数n,sum。
输出格式:
输出包括1行,为字典序最小的那个答案。
当无解的时候,请什么也不输出。(好奇葩啊)
输入输出样例
输入样例#1:
4 16
输出样例#1:
3 1 2 4
说明
对于40%的数据,n≤7;
对于80%的数据,n≤10;
对于100%的数据,n≤12,sum≤12345。
【思路】
Dfs+杨辉三角。
以题目数据为例:16=7+9=4+3+3+6=3+1+1+2+1+2+2+4=1*3 + 3*1 + 3*2 + 1*4
所以可以推出公式sum=∑ Yni*Ai
状态包括深度与和,知道了公式可以剪去 和 超过sum的搜索。
【代码】
1 #include<iostream> 2 #include<cstdlib> 3 using namespace std; 4 5 const int maxn = 14; 6 7 int n,M; 8 int A[maxn],vis[maxn]; 9 int yn[maxn]; 10 11 void get_yn() { 12 for(int i=0;i<n;i++){ 13 yn[i]=1; 14 for(int j=i/2;j>0;j--) yn[j]=yn[i-j]=yn[j]+yn[j-1]; 15 } 16 } 17 void dfs(int d,int sum) { 18 if(d==n && sum==M) { 19 for(int i=0;i<n;i++) cout<<A[i]<<" "; 20 exit(0); 21 } 22 if(sum>M) return ; 23 for(int i=1;i<=n;i++) if(!vis[i]) { 24 vis[i]=1; 25 A[d]=i; 26 dfs(d+1,sum+yn[d]*i); 27 vis[i]=0; 28 } 29 } 30 31 int main() { 32 ios::sync_with_stdio(false); 33 cin>>n>>M; 34 get_yn(); 35 dfs(0,0); 36 return 0; 37 }