POJ2229 [USACO05 Jan] Sum sets 递推(dp)

题目链接:传送门

显然是 dp。
d p [ i ] dp[i] dp[i]表示分解 i i i的方案数。
考虑怎样推出 d p [ i ] dp[i] dp[i]
i i i为奇数,则 i i i的分解式中必然有一个1。
若减去这个1,则变为 i − 1 i-1 i1的分解式。
任意 i − 1 i-1 i1的分解式后+1,则变为 i i i的分解式。
因此 i i i的分解方案与 i − 1 i-1 i1的分解方案是一一对应的。
所以 d p [ i ] = d p [ i − 1 ] dp[i]=dp[i-1] dp[i]=dp[i1]

i i i为偶数,则有两种情况:分解方案中有1和没有1。
如果有1,则1的数量至少有2个。
减去这两个1,发现变为了 i − 2 i-2 i2的分解。
若没有1,则分解式中的所有数均为2的倍数。
所以把所有数都除以2,变为了 i 2 \frac{i}{2} 2i的分解。
因此 d p [ i ] = d p [ i − 2 ] + d p [ i / 2 ] dp[i]=dp[i-2]+dp[i/2] dp[i]=dp[i2]+dp[i/2]

代码:

#include<stdio.h>
#include<cstring>
#include<algorithm>
#define re register int
using namespace std;
typedef long long ll;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
ll fastpow(ll b,ll p,ll k) {
	ll ans=1;
	while(p) {
		if(p&1)	ans=ans*b%k;
		b=b*b%k;
		p>>=1;
	}
	return ans;
}
const int Size=1000005;
const ll mod=1e9;
ll n,dp[Size];
int main() {
	n=read();
	dp[0]=dp[1]=1;
	for(re i=2; i<=n; i++) {
		if(i&1) {
			dp[i]=dp[i-1];
		} else {
			dp[i]=(dp[i-2]+dp[i>>1])%mod;
		}
	}
	printf("%lld",dp[n]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值