HDU 4651&&HDU 4658 五边形数定理

本文探讨了五边形数定理在HDU 4651和HDU 4658两个问题中的应用,涉及正整数分解和Integer Partition。通过欧拉函数和分割函数的关系,得出关于分割数的递推公式,并提供了相应的代码实现。

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

Partition

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1079    Accepted Submission(s): 630


Problem Description
How many ways can the numbers 1 to 15 be added together to make 15? The technical term for what you are asking is the "number of partition" which is often called P(n). A partition of n is a collection of positive integers (not necessarily distinct) whose sum equals n.

Now, I will give you a number n, and please tell me P(n) mod 1000000007.
 

Input
The first line contains a number T(1 ≤ T ≤ 100), which is the number of the case number. The next T lines, each line contains a number n(1 ≤ n ≤ 10 5) you need to consider.

 

Output
For each n, output P(n) in a single line.
 

Sample Input
  
4 5 11 15 19
 

Sample Output
  
7 56 176 490
 

Source

HDU4651求的是正整数分解,可以有重复元素。(没有重复元素的考虑dp,dp[i][j]表示j个数组成i的个数,有dp[i][j]=dp[i-j][j-1]+dp[i-j][j],分别考虑j在不在里面)。

首先,欧拉函数(1-x)(1-x^2)(1-x^3)…=1 – x - x^2 + x^5 + x^7 –x^12 – x^15…. X的系数为k*(3*k+1)/2,k*(3*k+1)/2留下来的次方正好是五边形数

然后欧拉函数的倒数是分割函数的母函数,假设p(k)为k的分割数,推过来就有

(1-x- x^2 +x^5 +x^7 –x^12 –x^15 + x^22 + x^26+ …)(1+ p(1)*x + p(2)*x^2 + p(3)*x^3 +…) = 1

比较等式两边的系数,可得到p(n)-p(n-1)-p(n-2)+p(n-5)+p(n-7)+…=0

代码:

#pragma warning(disable:4996)
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
typedef long long ll;

#define INF 0x333f3f3f
#define repp(i, n, m) for (int i = n; i <= m; i++)
#define rep(i, n, m) for (int i = n; i < m; i++)
#define sa(n) scanf("%d", &(n))

const ll mod = 1e9 + 7;
const int maxn = 1e5 + 5;
const double PI = acos(-1.0);

int n;
int k[maxn];
ll res[maxn];

void init()
{
    int i, j;
    int num = 0;
    for (i = 1; i <= 1000; i++)
    {
        for (j = 1; j <= 2; j++)
        {
            if (j & 1)
            {
                k[num] = i*(3 * i - 1) / 2;
                num++;            
            }
            else
            {
                k[num] = i*(3 * i + 1) / 2;
                num++;
            }
        }
    }
    res[0] = 1;
    for (i = 1; i <= 100000; i++)
    {
        for (j = 0; j < num; j++)
        {
            if (i - k[j] >= 0)
            {
                if (j % 4 < 2)
                {
                    res[i] += (res[i - k[j]]) % mod;
                    res[i] %= mod;
                }
                else
                {
                    res[i] -= (res[i - k[j]]) % mod;
                    res[i] = (res[i] % mod + mod) % mod;
                }
            }
            else
            {
                break;
            }
        }
    }
}

void solve()
{
    int n;
    sa(n);
    printf("%lld\n", res[n]);
}

int main() 
{
#ifndef ONLINE_JUDGE  
    freopen("i.txt", "r", stdin);
    freopen("o.txt", "w", stdout);
#endif
    init();
    int t;
    scanf("%d", &t);
    while (t--)
    {
        solve();
    }
    return 0;
}

Integer Partition

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 574    Accepted Submission(s): 267


Problem Description
Given n, k, calculate the number of different (unordered) partitions of n such that no part is repeated k or more times. 
 

Input
First line, number of test cases, T. 
Following are T lines. Each line contains two numbers, n and k. 

1<=n,k,T<=10 5
 

Output
T lines, each line contains answer to the responding test case. 
Since the numbers can be very large, you should output them modulo 10 9+7.
 

Sample Input
  
4 4 2 4 3 4 4 4 5
 

Sample Output
  
2 4 4 5
 

Source


HDU4658参考了http://blog.youkuaiyun.com/whai362/article/details/42530243这篇博客,这个题的母函数

G(x)=( 1 + x + x^2 +...+ x^(k-1) ) * ( 1 + x^2 +x^4 +...+ x^((k-1)*2) ) *...
    =(1-x^k)/(1-x) * (1-x^(k*2))/(1-x^2)* ...
    =( (1-x^k) * (1-(x^k)^2) *... ) / ((1-x) * (1-x^2) *... )
    =Q(x^k)/Q(x) (Q(x)为欧拉函数,根据上述定理可得)
    =Q(x^k)*P(x)
    =( 1 - x^k - (x^k)^2 + (x^k)^5 +(x^k)^7 -... ) * ( 1 + x + 2*x^2 + 3*x^3 + 5*x^4 + 7*x^5 + ... )

代码:

#pragma warning(disable:4996)
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
typedef long long ll;

#define INF 0x333f3f3f
#define repp(i, n, m) for (int i = n; i <= m; i++)
#define rep(i, n, m) for (int i = n; i < m; i++)
#define sa(n) scanf("%d", &(n))

const ll mod = 1e9 + 7;
const int maxn = 1e5 + 5;
const double PI = acos(-1.0);

int n;
int k[maxn];
int res[maxn];

void init()
{
    int i, j;
    int num = 0;
    for (i = 1; i <= 1000; i++)
    {
        for (j = 1; j <= 2; j++)
        {
            if (j & 1)
            {
                num++;
                k[num] = i*(3 * i - 1) / 2;
                
            }
            else
            {
                num++;
                k[num] = i*(3 * i + 1) / 2;
            }
        }
    }
    res[0] = 1;
    for (i = 1; i <= 100000; i++)
    {
        for (j = 1; j <= num; j++)
        {
            if (i - k[j] >= 0)
            {
                if ((j-1) % 4 < 2)
                {
                    res[i] += (res[i - k[j]]);
                    if (res[i] >= mod)
                        res[i] -= mod;
                }
                else
                {
                    res[i] -= (res[i - k[j]]);
                    if (res[i] < 0)
                        res[i] += mod;
                }
            }
            else
            {
                break;
            }
        }
    }
}

void solve()
{
    int n, kk;
    int i, j;
    int ans;

    sa(n), sa(kk);
    ans = res[n];
    for (i = 1;; i++)
    {
        int t = kk*k[i];
        if (t > n)
            break;
        if ((i - 1) % 4 < 2)
        {
            ans = (ans - res[n - t] + mod) % mod;
        }
        else
        {
            ans = (ans + res[n - t]) % mod;
        }
    }
    printf("%d\n", ans);
}

int main()
{
#ifndef ONLINE_JUDGE  
    freopen("i.txt", "r", stdin);
    freopen("o.txt", "w", stdout);
#endif

    init();
    int t;
    scanf("%d", &t);
    while (t--)
    {
        solve();
    }
    //system("pause");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值