oj 1161
提示:递推
比较经典的一道题,要是对递推比较敏感,那么可以一眼判断这是个递推题,很明显的一个特征就是答案只跟 n n n 有关,并且有继承性(转移性)。
考虑一个经典的模型,如果我们用 f[n]
表示长度为
n
n
n 时的答案,那么如何建立递推关系:
既然考虑递推关系,那么就显然我们需要考虑递推的意义,比如,假设:f[n-2]
对 f[n]
有贡献,那么这个贡献产生的意义是什么?
我们画个图:
首先我们定义下标:
然后我们考虑转移:
显然这就是意义,就是说,转移的意义就是:下标 n − 1 , n n-1, n n−1,n,应该怎么摆法。更加抽象一点,我们将包含的下标 n n n 的块看成一个不可分割的整体,也就是说,最后一块不能被竖着从任何地方分开。那么我们需要考虑的就是,包含下标 n n n 的一个整块的摆法。
经过分析,实验我们可以得到,一个整块只能是偶数长度,并且摆法方式只有两种,长度为2时有三种:
长度为偶数时,只有两种:边框固定,中间只能横着摆(不信自己试试,除了这个摆法,其他的摆法一定可以从中分开)
那么我们得到的递推式子就是:
f
(
n
)
=
3
∗
f
(
n
−
2
)
+
2
∗
∑
i
>
2
并且
i
是偶数
f
(
n
−
i
)
f(n) = 3*f(n-2) + 2 * \sum _{i>2 并且 i是偶数} f(n-i)
f(n)=3∗f(n−2)+2∗i>2并且i是偶数∑f(n−i)
#include <stdio.h>
typedef long long ll;
#define MOD 100003
int f[1003];
void init() {
f[0] = 1;
for (int i = 1; i <= 1000; ++i)
{
if (i >= 2) f[i] = f[i - 2];
for (int j = i - 2; j >= 0; j -= 2)
f[i] = (f[i] + f[j] * 2) % MOD;
}
}
int main()
{
init();
int n;
while (scanf("%d", &n) == 1 && n > 0)
{
printf("%d\n", f[n]);
}
return 0;
}
思考:如果 n 等 1 0 6 10^6 106 ,就不能用双重循环了,那么应该怎么做呢。
提示:前缀和,我们可以发现,实际上我们加的值就是与自己同奇偶性的长度的和。我们维护一个小于 n n n 的,奇数位置的和,偶数位置的和,然后在算答案时加起来即可。大家自己实现。