HDU 2709 Sumset DP 二进制

原题链接

题意


  • 给我们一个整数k,要求我们将k分成若干个二的整数幂(1, 2, 4, 8...)的加和形式,问我们所有的分法中,本质不同(即某个2的幂的数量不同)的形式有多少种,k最多为1000000,输出答案的后9位数

思路


  • 由k范围,我们寻找线性算法,可以从题中给出的k == 7的例子来分析,如下图


  • 可以看到,由于7余2等于1,而1不可分解,所以每一行都有一个1,所以显然,我们如果给7减去1之后,结果将仍然是6种,所以我们可以发现,k为奇数时的结果就是k - 1的结果。

  • 然后我们抛开最左边的一列1,从下往上看可以发现,第5 6行的所有数可以都除以2,然后得((1 1 1),(1 2)),这正是3的分解结果

  • 而再往上看1234行,我们发现左边两列都是1,可以看做是第五行中,一个2分解的结果,于是忽略这两列,然后可以发现,从(1,1,1,1)到(4)正是4的分解结果,也就是6 - 2(因为忽略了两行1)的结果

  • 考虑k等于其他偶数时,我们可以发现上述情况是一定会有的 —— 我们总是会分出一个最小值为2的序列,然后这个序列总体除以2,就是k / 2的分解结果,然后我们将其中的一个2分解为2个1, 然后剩下的就是k - 2的分解结果,这样就包含了全部情况了

  • 所以k为奇数时, F[k] = F[k - 1]的答案,而k为偶数时,F[k] = F[k >> 1] + F[k - 2]

提示


  • 这道题有提到single line,但是仍然有多组数据

  • 虽然题目要求后9位,但是在此题中直接%1e9是没有问题的,可能是出题人没有想到

AC代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define lowbit(x) (x&(-x))

using namespace std;

const long long modd = 1000000000;

long long ff[1000005];
int n;

int main()
{
	ff[0] = 1;
	for (long long j = 1; j <= 1000000; ++j)
	{
		if (j & 1)
		{
			ff[j] = ff[j - 1];
		}
		else
		{
			ff[j] = ((ff[j] + ff[j - 2]) % modd + ff[j >> 1]) % modd;
		}
	}
	while (scanf("%d", &n) == 1)
	{
		printf("%lld\n", ff[n]);
	}
	return 0;
}

posted @ 2021-02-22 18:38  _int_me  阅读(53)  评论(0编辑  收藏  举报