HDU1028_整数的划分

本文探讨了如何使用五边形定理解决数的划分问题,通过递归算法实现,考虑到允许重复数字及正数划分的特点,提供了两种编程实现方案,一种适用于长整型数范围,另一种则针对任意取模情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.题目链接。题意十分的简洁,就是给你一个数,找出把它划分成几个小的数加起来的方法。当然了,这里的小是不允许出现负数的。(当然了,一定范围内出现负数还是可以的,这个以后我们再讨论)。这里还有另外一个很重要的条件就是允许划分数来的小的数字可以相同的。这也是一个很重要的特点。满足上边的两个特点的,我们就可以使用五边形定理。至于什么是五边形定理,先留个坑。我先给个板子来解决了这道题。

#include<iostream>
#define ll long long
const ll N = 100005;
#pragma warning(disable:4996)
ll n, f[N];
ll solve(ll n)
{
	if (f[n]) return f[n];
	for (ll i = 1; i*(i * 3 - 1) / 2 <= n; i++)
	{
		if (!(i & 1))
		{
			if (i*(i * 3 - 1) / 2 <= n)
				(f[n]-=solve(n - i * (i * 3 - 1) / 2)) ;
			if (i*(i * 3 + 1) / 2 <= n)
				(f[n] -=solve(n - i * (i * 3 + 1) / 2)) ;
		}
		else
		{
			if (i*(i * 3 - 1) / 2 <= n) (f[n] += solve(n - i * (i * 3 - 1) / 2)) ;
			if (i*(i * 3 + 1) / 2 <= n) (f[n] += solve(n - i * (i * 3 + 1) / 2)) ;
		}
	}
	return f[n];
}
int  main()
{
	ll T;
	f[0] = f[1] = 1;
	while (~scanf("%lld", &T))
	{
		printf("%lld\n", solve(T));
	}return 0;
}

但是一般来说都是带取模的:所以这个在任意取模的情况写的写法是这样的:

const int N = 100005;
const int MOD = 1000000007;
#pragma warning(disable:4996)
int n, f[N];
int solve(int n)
{
if (f[n]) return f[n];
for (int i = 1; i*(i * 3 - 1) / 2 <= n; i++)
{
if (!(i & 1))
{
if (i*(i * 3 - 1) / 2 <= n)
(f[n] += MOD - solve(n - i * (i * 3 - 1) / 2)) %= MOD;
if (i*(i * 3 + 1) / 2 <= n)
(f[n] += MOD - solve(n - i * (i * 3 + 1) / 2)) %= MOD;
}
else
{
if (i*(i * 3 - 1) / 2 <= n) (f[n] += solve(n - i * (i * 3 - 1) / 2)) %= MOD;
if (i*(i * 3 + 1) / 2 <= n) (f[n] += solve(n - i * (i * 3 + 1) / 2)) %= MOD;
}
}
return f[n];
}
int main()
{
int T;
scanf("%d", &T);
f[0] = f[1] = 1;
while (T--)
{
scanf("%d", &n);
printf("%d\n", solve(n));
}
return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值