装飾フェンス(POJ-1037、DPを数える)

1.タイトルリンク:

POJ-1037

2.トピックの主なアイデア:

2つの整数n、cを入力します

語彙の順序cで1〜nの**配置を出力する必要があります。

**配置とは、長さがn、各番号が1〜nで、番号が繰り返されず、サイズがずらされた配置を指します。

3.分析:

「トライアル法」は、cのランキングを決定するために使用することができます。

具体的には、最初の数字のサイズを列挙できます

最初の数がa [1]の場合、n-1個の数で構成される**置換スキームの数をtとします。

t> = cの場合、最初の数値はa [1]です。

それ以外の場合は、最初の数値を大きくする必要があることを意味し、c-t、a [1]を1ずつ増やします。

上記のプロセスを繰り返して最初の数値のサイズを決定し、同様にすべての数値のサイズを決定します。

したがって、最初にtを前処理する必要があります。

f [i] [j] [k]は、i個の相互に異なる番号を表します。ここで、左端の番号はi個の番号の中で昇順でjにランク付けされ、左端の番号はlow(0)/ high( 1)ビット、1時間あたりのプログラム数。

状態遷移方程式は非常に単純です。詳細については、コードを参照してください。

PS:最初の数字のサイズを決定するときは、最初にf [n] [j] [1]を列挙し、次にf [n] [j] [1]を列挙する必要があります。これは、両方が条件を満たす場合だからです。の場合、1が高い語彙の順序が小さいことは明らかです。

4.コードの実装:

#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;
}

 

おすすめ

転載: blog.csdn.net/The___Flash/article/details/104827017