A decorative fence (POJ-1037, counting DP)

1. Title link:

POJ-1037

2. The main idea of ​​the topic:

Enter two integers n, c

It is required to output the ** permutation with lexicographic order c from 1 to n.

**Arrangement refers to the arrangement with length n, each number from 1 to n, and the numbers are not repeated and the size is staggered.

3. Analysis:

The "trial method" can be used to determine the ranking of c.

Specifically, we can enumerate the size of the first number

When the first number is a[1], let the number of the ** permutation scheme composed of n-1 numbers be t

If t >= c, then the first number is a[1]

Otherwise, it means that the first number should be larger. In this case, let c-t, a[1] increase by 1.

Repeat the above process to determine the size of the first number, and similarly determine the size of all numbers.

So we should preprocess t first.

f[i][j][k] represents i mutually different numbers, where the leftmost number is ranked j among the i numbers in ascending order, and the leftmost number is low(0)/high( 1) Bits, the number of programs per hour.

The state transition equation is very simple, see the code for details.

PS: When determining the size of the first number, you should first enumerate f[n][j][1], and then enumerate f[n][j][1], because when both meet the conditions When, it is obvious that the lexicographic order with 1 as the high order is smaller.

4. Code implementation:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long ll;

const int M = (int)20;

bool vis[M + 5];
ll f[M + 5][M + 5][2];

void init()
{
    f[1][1][0] = f[1][1][1] = 1;
    for(int i = 2; i <= M; ++i)
    {
        for(int j = 1; j <= i; ++j)
        {
            for(int k = j; k <= i - 1; ++k) f[i][j][0] += f[i - 1][k][1];
            for(int k = 1; k <= j - 1; ++k) f[i][j][1] += f[i - 1][k][0];
        }
    }
}

int main()
{
    init();
    int T;
    scanf("%d", &T);
    while(T--)
    {
        memset(vis, 0, sizeof(vis));
        int n; ll c;
        scanf("%d %lld", &n, &c);
        int ls, k;
        for(int j = 1; j <= n; ++j)
        {
            if(f[n][j][1] >= c)
            {
                ls = j;
                k = 1;
                break;
            }
            else    c -= f[n][j][1];
            if(f[n][j][0] >= c)
            {
                ls = j;
                k = 0;
                break;
            }
            else    c -= f[n][j][0];
        }
        vis[ls] = 1;
        printf("%d", ls);
        for(int i = 2; i <= n; ++i)
        {
            k ^= 1;
            int j = 0;
            for(int l = 1; l <= n; ++l)
            {
                if(vis[l])  continue;
                ++j;
                if(k == 0 && ls > l || k == 1 && ls < l)
                {
                    if(f[n - i + 1][j][k] >= c)
                    {
                        ls = l;
                        break;
                    }
                    else    c -= f[n - i + 1][j][k];
                }
            }
            vis[ls] = 1;
            printf(" %d", ls);
        }
        printf("\n");
    }
    return 0;
}

 

Guess you like

Origin blog.csdn.net/The___Flash/article/details/104827017