POJ1037 A Decorative Fence

一道计数类\(DP\)

原题链接

先用\(DP\)计算方案数,再枚举木板,并将\(C\)不断减去方案数,直到得出所求方案。
定义\(f[i][j][k]\)表示用\(i\)块木板构成栅栏,其中最左边的木板高度从小到大排在第\(j\)块,\(k\)表示这块木板是低位还是高位(低位为\(0\),高位为\(1\))。

\(\qquad\qquad f[i][j][0]=\sum\limits_{k=j}^{i-1}f[i-1][k][1]\)

\(\qquad\qquad f[i][j][1]=\sum\limits_{k=1}^{j-1}f[i-1][k][0]\)

然后就可以枚举木板,当枚举到第\(i\)块木板,这块木板剩余木板中排名为\(j\),若\(f[n-i+1][j][k]<C\),则将\(C\)减去\(f[n-i+1][j][k]\),否则就说明第\(i\)个位置就是这块木板。

#include<cstdio>
#include<cstring>
using namespace std;
const int N = 22;
typedef long long ll;
ll f[N][N][2];
bool v[N];
ll re()
{
    ll x = 0;
    char c = getchar();
    bool p = 0;
    for (; c<'0' || c>'9'; c = getchar())
        p = (c == '-' || p) ? 1 : 0;
    for (; c >= '0'&&c <= '9'; c = getchar())
        x = x * 10 + (c - '0');
    return p ? -x : x;
}
int main()
{
    int i, j, k, n, t, la, o;
    ll m;
    t = re();
    f[1][1][0] = f[1][1][1] = 1;
    for (i = 2; i <= 20; i++)
        for (j = 1; j <= i; j++)
        {
            for (k = 1; k < j; k++)
                f[i][j][1] += f[i - 1][k][0];
            for (k = j; k < i; k++)
                f[i][j][0] += f[i - 1][k][1];
        }
    while (t--)
    {
        n = re();
        m = re();
        memset(v, 0, sizeof(v));
        for (i = 1; i <= n; i++)
        {
            if (f[n][i][1] >= m)
            {
                la = i;
                k = 1;
                break;
            }
            else
                m -= f[n][i][1];
            if (f[n][i][0] >= m)
            {
                la = i;
                k = 0;
                break;
            }
            else
                m -= f[n][i][0];
        }
        v[la] = 1;
        printf("%d", la);
        for (i = 2; i <= n; i++)
        {
            k ^= 1;
            o = 0;
            for (j = 1; j <= n; j++)
                if (!v[j])
                {
                    o++;
                    if ((!k&&j < la) || (k&&j > la))
                        if (f[n - i + 1][o][k] >= m)
                        {
                            la = j;
                            break;
                        }
                        else
                            m -= f[n - i + 1][o][k];
                }
            v[la] = 1;
            printf(" %d", la);
        }
        printf("\n");
    }
    return 0;
}

ps:因为我用的是\(VS\),所以代码会自动补空格,而我本来的风格是没有空格的。

猜你喜欢

转载自www.cnblogs.com/Iowa-Battleship/p/9502265.html