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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值