aaa第一道英语题
题目描述
FJ
and his cows enjoy playing a mental game. They write down the numbers from 1 toN(1≤N≤10) in a certain order and then sum adjacent numbers to produce a new list with one fewer number. They repeat this until only a single number is left. For example, one instance of the game (when N=4) might go like this:
3 1 2 4
4 3 6
7 9
16
Behind FJ
's back, the cows have started playing a more difficult game, in which they try to determine the starting sequence from only the final total and the number N. Unfortunately, the game is a bit above FJ
's mental arithmetic capabilities.
Write a program to help FJ
play the game and keep up with the cows.
输入格式
Line 1: Two space-separated integers: N and the final sum.
输出格式
Line 1: An ordering of the integers 1..N that leads to the given sum. If there are multiple solutions, choose the one that is lexicographically least, i.e., that puts smaller numbers first.
题意翻译
有这么一个游戏:
写出一个 1∼n 的排列 a,然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少 1,直到只剩下一个数字位置。
下面是一个例子:
- 3,1,2,4;
- 4,3,6;
- 7,9;
- 16。
最后得到 16 这样一个数字。
现在想要倒着玩这样一个游戏,如果知道 n,以及最后得到的数字的大小 sum,请你求出最初序列 ai(应该是一个 1∼n 的排列)。若答案有多种可能,则输出字典序最小的那一个。
我们称序列 a=⟨a1,a2,⋯,an⟩ 的字典序小于序列 b=⟨b1,b2,⋯,bn⟩ 的字典序,当且仅当存在一个位置 p,满足 a1=b1,a2=b2,⋯,ap−1=bp−1,ap<bp。
输入输出样例
输入 #1复制
4 16
输出 #1复制
3 1 2 4
说明/提示
- For 40% of the data, 1≤n≤7;
- For 80% of the data, 1≤n≤10;
- For 100% of the data, 1≤n≤12, 1≤sum≤12345.
看了一下题解,居然没人用stl,next_permutation生成下一个排列不就直接完事了嘛。
**超时!**是的,直接next_permutation会超时,但优化一下就亦可赛艇了。。
具体措施如下:
当发现当前的和值大于目标时,那么再next_permutation是肯定超的,应该跳过去。
怎么跳呢?我们把从发现超过目标时所计算到的位开始,一直到结束的所有位排序成从大到小,下次再next_permutation的时候就能完美跳过这一段了。perfect!
来来来,一起念,stl大法好,简单粗暴没得跑。
具体上代码,尽量注释。
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
int num_a[15];
int log_a[15][15];
int cmp(int t1,int t2){
return t1>t2;
}
int main() {
//freopen("test.in","r",stdin);
int n,sum;
cin>>n>>sum;
for(int i=1; i<=n; i++) num_a[i]=i;
for(int i=1;i<=n;i++)log_a[i][1]=log_a[i][i]=1;
for(int i=3;i<=n;i++){
for(int k=1;k<=(i-1)/2;k++){
log_a[i][k+1]=log_a[i][i-k]=log_a[i-1][k]+log_a[i-1][k+1];
}
}
//以上先弄出一个杨辉三角来,这是必须的。
do {
int out_a=0;
int num_tmp[15];
memcpy(num_tmp,num_a,sizeof(num_tmp));
int tsum=0;
for(int i=1;i<=n;i++){
tsum+=num_tmp[i]*log_a[n][i];
if(tsum>sum){//没错,关键就这里,发现从当前开始的i位开始往后累加都会超过预期,就把它从大到小排一遍,再next的时候就能跳过这一段了
sort(num_a+i,num_a+n+1,cmp);
out_a=1;
break;
}
}
if(out_a) continue;
if(tsum==sum){
for(int i=1;i<=n;i++){
cout<<num_a[i]<<" ";
}
break;
}
} while(next_permutation(num_a+1,num_a+1+n));
}