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;
}
posted on 2018-08-19 19:27 Iowa_Battleship 阅读(258) 评论(1) 编辑 收藏 举报