【题解】P5879 题解

P5879 题解

简单的 DP 题目。

DP 的话,首先你要弄明白怎么转移。

当时我是在某场模拟赛看到了这道题,我就去枚举了一下当 nn33 时的所有情况。

这里明确一下,第 xx 行代表有 xx 个格子的那一行。

我们是怎么枚举的呢?小学的时候老师告诉过我们,枚举要有序。放到这题来讲,我们先枚举第三行放三个,再枚举第三行放二个,最后再枚举第三行放一个和不放。如果第三行放三个,那么还要继续枚举第二行放二个、一个和不放。

一般化地来讲,当我们枚举第 ii 行放 jj 个时,我们就要枚举第 i1i-1 行放 00jj 的情况。当然,有时候由于第 i1i-1 行只有 i1i - 1 个格子,所以事实上放不到 jj 个。也就是说,实际上要枚举的是 i1i-1 行放 00min(i1,j)\min(i - 1,j) 的情况。

于是递推式先出来了:

f(i,j)=f(i1,0)+f(i1,1)+f(i1,2)++f(i1,k)f(i,j)=f(i-1,0)+f(i-1,1)+f(i-1,2)+\ldots+f(i-1,k)

其中 k=min(i1,j)k = \min(i - 1,j)

此时还要注意,当我们枚举到最后一个的时候,也就是第 11 格的时候,只有两种情况:放一个和不放,这个时候不用枚举,直接就是一种情况,即 f(1,1)=f(1,0)=1f(1,1)=f(1,0)=1

直接按式子推就可以了。

最后的答案是 f(n,0)+f(n,1)++f(n,n)f(n,0)+f(n,1)+\ldots+f(n,n)

代码如下:

int n;
cin >> n;
f[1][1] = f[1][0] = 1;
for(int i = 2;i <= n;i++)
{
    for(int j = 0;j <= i;j++)
    {
        for(int k = 0;k <= min(j, i - 1);k++)
        {
            f[i][j] += f[i - 1][k];
        }
    }
}
int sum = 0;
for(int i = 0;i <= n;i++)
{
    sum += f[n][i];
}
cout << sum - 1 << endl;

但是需要注意,这题高精度。

由于我不想写高精度,于是写了一个打表的 Python 程序,如下:

for n in range(1,101):
    f=[]
    for i in range(0,211):
        q=[]
        for j in range(0,211):
            q.append(0)
        f.append(q)
    f[1][1] = f[1][0] = 1
    for i in range(2, n + 1):
        for j in range(i + 1):
            for k in range(min(j, i-1)+1):
                    f[i][j] += f[i - 1][k]
    sum = 0
    for i in range(n + 1):
        sum += f[n][i]
    print('"'+str(sum - 1)+'",',end='')

这个本质上就是计算 11100100 的答案,由于 Python 自带高精度,所以该程序可以得到正确的答案。

然后把这个打出来的表写进去就可以了。

#include <iostream>
#include <string>
using namespace std;
const int N = 2e2 + 10;

string t[N] = /*表见https://www.luogu.com.cn/paste/4u4gehh1*/;

int main()
{
    int n;
    cin >> n;
    cout << t[n] << endl;
    return 0;
}
posted @ 2023-09-09 16:56  邻补角-SSA  阅读(13)  评论(0)    收藏  举报  来源