HDU 2709 Sumset DP 二進制

原題連接

php

題意


  • 給咱們一個整數k,要求咱們將k分紅若干個二的整數冪(1, 2, 4, 8...)的加和形式,問咱們全部的分法中,本質不一樣(即某個2的冪的數量不一樣)的形式有多少種,k最多爲1000000,輸出答案的後9位數

思路


  • 由k範圍,咱們尋找線性算法,能夠從題中給出的k == 7的例子來分析,以下圖


    ios

  • 能夠看到,因爲7餘2等於1,而1不可分解,因此每一行都有一個1,因此顯然,咱們若是給7減去1以後,結果將仍然是6種,因此咱們能夠發現,k爲奇數時的結果就是k - 1的結果。

    算法

  • 而後咱們拋開最左邊的一列1,從下往上看能夠發現,第5 6行的全部數能夠都除以2,而後得((1 1 1),(1 2)),這正是3的分解結果

    spa

  • 而再往上看1234行,咱們發現左邊兩列都是1,能夠看作是第五行中,一個2分解的結果,因而忽略這兩列,而後能夠發現,從(1,1,1,1)到(4)正是4的分解結果,也就是6 - 2(由於忽略了兩行1)的結果

    code

  • 考慮k等於其餘偶數時,咱們能夠發現上述狀況是必定會有的 —— 咱們老是會分出一個最小值爲2的序列,而後這個序列整體除以2,就是k / 2的分解結果,而後咱們將其中的一個2分解爲2個1, 而後剩下的就是k - 2的分解結果,這樣就包含了所有狀況了

    blog

  • 因此k爲奇數時, F[k] = F[k - 1]的答案,而k爲偶數時,F[k] = F[k >> 1] + F[k - 2]

    get

提示


  • 這道題有提到single line,可是仍然有多組數據

    string

  • 雖然題目要求後9位,可是在此題中直接%1e9是沒有問題的,多是出題人沒有想到

    it

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;
}
相關文章
相關標籤/搜索