POJ 1037 DP

题目链接: http://poj.org/problem?id=1037

分析: 很有分量的一道DP题!!!

         (参考于:http://blog.csdn.net/sj13051180/article/details/6669737 )

 

#include <iostream>

#include <cstdio>

#include <cmath>

#include <cstdlib>

#include <string>

#include <cstring>

#include <algorithm>

#include <iomanip>

using namespace std;



long long up[25][25];

long long down[25][25];

long long ans[25];



void getfirst(long long n,long long c,bool u){

    if(n==0) return ;

    long long sum=0,t;

    if(!u) { //前一步是up,当前步要down

        t=ans[n+1];

        while(sum+down[n][t]<c)

            sum+=down[n][t++];

    } else { //前一步是down,当前步要up

        t=1;

        while(sum+up[n][t]<c)

            sum+=up[n][t++];

    }

    ans[n]=t;  //定位

    getfirst(n-1,c-sum,!u);  //搜索下一位

    for(int i=1;i<n;++i)

        if(ans[i]>=t) ++ans[i];

}



void Init(){

    up[1][1]=down[1][1]=1;

    for(int i=2; i<=20; ++i)

        for(int j=1; j<=i; ++j) {

            up[i][j]=down[i][j]=0;

            for(int k=j; k<=i-1; ++k)

                up[i][j]+=down[i-1][k];

            for(int k=1; k<=j-1; ++k)

                down[i][j]+=up[i-1][k];

        }

}

int main(){

    Init();

    int T; scanf("%d",&T);

    while(T--){

        long long c,n;

        scanf("%lld%lld",&n,&c); 

        

        long long sum=0,t=1;

        while(sum+up[n][t]+down[n][t]<c){

            sum+=up[n][t]+down[n][t];

            ++t;

        }

        ans[n]=t;  //定位首位

        //搜索下一位

        if(sum+down[n][t]<c)                      //在up中

            getfirst(n-1,c-sum-down[n][t],false);

        else                                      //在down中 

            getfirst(n-1,c-sum,true);

        for(int i=1;i<n;++i)// 比如当n=5时, 第一个选了t=3, 还有1,2,4,5 后面会对应到1,2,3,4, 大于t的都相对-1, 最终要+1 

            if(ans[i]>=t) ++ans[i];

            

        printf("%lld",ans[n]);

        for(int i=n-1;i>=1;--i)

            printf(" %lld",ans[i]);

        puts("");

    }

    return 0;

}








 



 

你可能感兴趣的:(poj)