整数拆分

hdu 1085 Holding Bin-Laden Captive!

hdu 1398 Square Coins

入门级基础题

hdu 4651 Partition

这该算是数论中的经典题了。网上关于这题的解法大同小异,都不外乎利用生成函数(母函数)和五边形定理。
作为初学者算是费了不少精力才搞懂。
关于生成函数的推导是重点,本题中:
∑p(n)x^n= (1+x^1+x^2+x^3...)(1+x^2+x^4+x^6...)(1+x^3+x^6...)
等比数列求和得 ∑p(n)x^n= (1+x^1+x^2+x^3...)(1+x^2+x^4+x^6...)(1+x^3+x^6...) = 
(1-x^(+∞/1 + 1))(1-x^(+∞/2 + 1))... / (1-x)(1-x^2)(1-x^n)
∵ |x|<1
 ∑p(n)x^n = 1 / (1-x)(1-x^2)(1-x^n)
结合五边形定理∑p(n)x^n = 1 / (1-x^1-x^2+x^5+x^7...)
即:(p(0) + p(1)x^1 + p(2)x^2 ... )(1-x^1-x^2+x^5+x^7...) = 1
∴ p(n)x^n + p(n-1)x^(n-1)*(-x^1) + p(n-2)x^(n-2)*(-x^2) + p(n-5)x^(n-5)*(x^5)... = 0
∴ p(n) = p(n-1) + p(n-2) - p(n-5) - p(n-7)...
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 100005;
typedef __int64 ll;
ll MOD = 1000000007;
ll num[MAXN];
void init()
{
    num[0] = num[1] = 1;
    for (int i = 2; i<= 100000; ++i)
    {
        ll flg = 1;
        for (int k = 1; ;++k)
        {
            int a = i - (3*k-1)*k/2, b = i - (3*k+1)*k/2;
            ll s1, s2;
            if (a < 0) break;
            s1 = num[a];
            if (b < 0) s2 = 0;
            else s2 = num[b];
            num[i] = (num[i]+flg*(s1+s2))%MOD;
            flg = 0-flg;
        }
        num[i] = (num[i]+MOD)%MOD;
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    int t;
    scanf("%d", &t);
    init();
    while(t--)
    {
        int a;
        scanf("%d", &a);
        printf("%I64d\n", num[a]);
    }
    return 0;
}


hdu 4658 Integer Partition

该题是上题的加强版,而且需要用到上题中推出的公式
具体可参见 http://blog.csdn.net/zhoufenqin/article/details/9821617 ,写的非常详细
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 100005;
typedef __int64 ll;
ll MOD = 1000000007;
ll num[MAXN];
void init()
{
	num[0] = num[1] = 1;
	for (int i = 2; i<= 100000; ++i)
	{
		ll flg = 1;
		for (int k = 1; ;++k)
		{
			int a = i - (3*k-1)*k/2, b = i - (3*k+1)*k/2;
			ll s1, s2;
			if (a < 0) break;
			s1 = num[a];
			if (b < 0) s2 = 0;
			else s2 = num[b];
			num[i] = (num[i]+flg*(s1+s2))%MOD;
			flg = 0-flg;
		}
		num[i] = (num[i]+MOD)%MOD;
	}
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
	int t;
	scanf("%d", &t);
	init();
	while(t--)
	{
		int a, k;
		scanf("%d%d", &a, &k);
		ll res = num[a];
		for (int j = 1, f = -1; ; ++j, f=0-f)
		{
			int c = (3*j-1)*j/2*k, d = (3*j+1)*j/2*k;
			ll s1, s2;
			if (c > a) break;
			s1 = f*num[a-c];
			if (d > a) s2 = 0;
			else s2 = f*num[a-d];
			res = (res + s1 + s2)%MOD;
		}
		res = (res+MOD)%MOD;
		printf("%I64d\n", res);
	}
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值