//poj 1037 A decorative fence 经典的DP+计数 /* 题解:dp[len][i][0]表示长度为len的序列,第i长的棒起头,前两根下降的方案数;dp[len][i][1]表示相应的前两根上升的方案数 只要想到方案中只要求交替上升下降,只与长度的相对高低有关系就不难想出这样的dp方法了。预处理完后就是一般的计数方法了。 心得:本题又暴露出自己的不自信,明明是正确的方法,只是实现上出现也小bug,就怀疑自己。看来心理素质还是比较重要。 */ #include <iostream> using namespace std; int n; __int64 m; __int64 dp[21][21][2]; int mark[21]; int main() { dp[1][1][0]=dp[1][1][1]=1; for (int len=2;len<=20;len++) for (int i=1;i<=len;i++) { for (int j=1;j<i;j++) dp[len][i][0]+=dp[len-1][j][1]; for (int j=i;j<len;j++) dp[len][i][1]+=dp[len-1][j][0]; } /* for (int i=1;i<=20;i++) printf("%I64d %I64d/n",dp[20][i][0],dp[20][i][1]); */ int t; scanf("%d",&t); while (t--) { scanf("%d%I64d",&n,&m); int l=1,r=n,j,finded=0; memset(mark,0,sizeof(mark)); for (int i=1;i<=n && !finded;i++) { for (j=0;j<2;j++) { m-=dp[n][i][j]; if (m<=0) { m+=dp[n][i][j]; mark[i]=1; printf("%d",i); if (j==0) l=1,r=i-1; else l=i+1,r=n; finded=1; break; } } } j^=1; for (int len=n-1;len>=1;len--) { int num=0; for (int i=1;i<l;i++) if (!mark[i]) ++num; for (int i=l;i<=r;i++) if (!mark[i]) { num++; m-=dp[len][num][j]; if (m<=0){ m+=dp[len][num][j]; mark[i]=1; printf(" %d",i); if (j==0) l=1,r=i-1; else l=i+1,r=n; j^=1; break; } } } printf("/n"); } system("pause"); return 0; }