P1118 [USACO06FEB]数字三角形

题目描述:

有这么一个游戏:

写出一个1~N的排列a[i],然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少1,直到只剩下一个数字位置。下面是一个例子:

3 1 2 4

4 3 6

7 9 16 最后得到16这样一个数字。

现在想要倒着玩这样一个游戏,如果知道N,知道最后得到的数字的大小sum,请你求出最初序列a[i],为1~N的一个排列。若答案有多种可能,则输出字典序最小的那一个。

[color=red]管理员注:本题描述有误,这里字典序指的是1,2,3,4,5,6,7,8,9,10,11,12

而不是1,10,11,12,2,3,4,5,6,7,8,9[/color]

输入输出格式

输入格式:

两个正整数n,sum。

输出格式:

输出包括1行,为字典序最小的那个答案。

当无解的时候,请什么也不输出。(好奇葩啊)

以下杨辉三角的系数推算参考 Sweetlemon(洛谷网)

如果n为4,那么sum是a+3b+3c+d。

如果n为5,那么sum是a+4b+6c+4d+e。

如果n为6,那么sum是a+5b+10c+10d+5e+f。

观察各项的系数,你发现了什么?


如果你有敏锐的数学眼光,你会发现,各项系数恰与杨辉三角有关!

那么我们就可以枚举每个a,b,c,...,逐一与sum比较,就可以得出答案了。


首先,计算杨辉三角。

我使用的是这样一个公式(状态转移方程): 

如果杨辉三角的状态转移方程推算出来,这道题就是一个很简单的dfs,贴代码

#include
using namespace std;
int n,sum;
int a[100],book[100],flag;
int ans[100];
void dfs(int step,int su) //step表示第几个数,su表示当前总和 
{
if(flag)
return;
if(su>sum)
return ;
if(step==n+1)
{
if(su==sum)
{
for(int i=1;i<=n;i++)
cout< flag=1;
}
else 
return ;
}
for(int i=1;i<=n;i++)
{
if(!book[i])
{
book[i]=1;
ans[step]=i;
dfs(step+1,su+a[step]*i);
book[i]=0;
}
}
}
int main()
{
cin>>n>>sum;
a[1]=a[n]=1;
for(int i=2;i*2<=n+1;i++)
a[i]=a[n-i+1]=(n-i+1)*a[i-1]/(i-1); //杨辉三角状态转移 
dfs(1,0);
return 0;
}

你可能感兴趣的:(搜索)