天天看点

HDU1028_整数的划分

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