jzoj 1261 数字游戏

来源:互联网 发布:win10优化驱动器要几遍 编辑:程序博客网 时间:2024/06/05 16:01

Description

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觉得没意思,就想和你玩,当然,你可以用一种叫做“电子计算机”的东西帮你。

Input

本题有多组数据,对于每组数据:一行两个整数n(0< n<=20),t即最后求出来的数。两个0表示输入结束。

Output

对于每组测试数据输出一行n个整数,用空格分开,行尾无多余空格,表示求出来的满足要求的1~n的一个排列。

Sample Input

4 163 90 0

Sample Output

3 1 2 41 3 2

Data Constraint

对于30%的数据,保证该组里的每个N都不超过10。对于100%的数据,保证有每个N不超过20,且每组数据的个数不超过10。

Solution

可以通过观察发现,t是由这个n的排列的每个数乘上一个系数得到,系数是杨辉三角第n行。若直接dfs,就会超时,所以需要剪枝。1.若已经找到答案,结束dfs2.若当前的和加上后面能算出的最大值仍小于t,返回上层。3.若当前的和加上后面能算出的最小值仍大于t,返回上层。4.由于系数对称,而要找字典序最小的序列,所以,当系数相同时,小的数一定在前面。
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>using namespace std;#define N 25int f[N][N];int q[N],t[N],x[N];int n,m;bool b;void pre(){    memset(f,0,sizeof(f));    f[1][1]=1;    for (int i=2;i<N;++i)      for (int j=1;j<=i;++j)        f[i][j]=f[i-1][j-1]+f[i-1][j];}bool comp(int x,int y){    return x>y;}bool pd(int dep,int s){    int an=s;    for (int i=dep;i<=n;++i)      x[i-dep]=f[n][i];    sort(x,x+n-dep+1,comp);    /*for (int i=0;i<=n-dep;++i)      printf("%d ",x[i]);    printf("\n");*/    int j=0;    for (int i=n;i>=1;--i)      if (t[i]==0)      {        an+=i*x[j];        j++;      }    //printf("max=%d\n",an);    if (an<m) return true;    an=s;    j=0;    for (int i=1;i<=n;++i)      if (t[i]==0)      {        an+=i*x[j];        j++;      }    //printf("min=%d\n",an);    if (an>m) return true;    return false;}void dfs(int dep,int s){    /*printf("%d,%d\n",dep,s);    for (int i=1;i<=n;++i)      printf("%d ",t[i]);    printf("\n");*/    if (b==1) return;    if (dep==n)    {        if (s==m)        {            for (int i=1;i<=n;++i)              printf("%d ",q[i]);            printf("\n");            b=1;        }        return;    }    if (s>m) return;    if (pd(dep+1,s)) return;    if (dep>n/2 && q[dep]<q[n-dep+1]) return;    for (int i=1;i<=n;++i)      if (t[i]==0)      {        t[i]=1;        q[dep+1]=i;        dfs(dep+1,s+i*f[n][dep+1]);        t[i]=0;      }}int main(){    freopen("easy.in","r",stdin);    freopen("easy.out","w",stdout);    pre();    scanf("%d%d",&n,&m);    while (not(n==0 && m==0))    {        b=0;        memset(t,0,sizeof(t));        dfs(0,0);        scanf("%d%d",&n,&m);    }    return 0;}