整数拆分学习

游客请绕路:

http://www.cnblogs.com/xin-hua/p/3242428.html

http://blog.csdn.net/u013368721/article/details/45827909

结论:

1、不加限制答案:f[n]=∑(-1)^(k-1)*(f[n-k*(3*k-1)/2]+f[n-k*(3*k+1)/2])

  其中n-k*(3*k-1)/2>=0,n-k*(3*k+1)/2>=0     注意两个条件要分开判断,有大于0的就加上相应的f。

2、

当限定将表示成刚好个正整数之和时,可以表示为。显然,

对于

 = 最接近的正整数。

3、

令Fk(n)表示n的满足数拆分时每种数的个数小于等于k的数拆分方案数。则有:

Fk(n)=Px(n)−Px(n−k)−Px(n−2k)+Px(n−5k)+...

做法其实是构造生成函数 。。。。。

hdu 4651  求把n拆开的方案数

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
long long f[100010] ;
//:f[n]=∑(-1)^(k-1)*(f[n-k*(3*k-1)/2]+f[n-k*(3*k+1)/2])
/*
其中n-k*(3*k-1)/2>=0,n-k*(3*k+1)/2>=0;

        注意两个条件要分开判断,有大于0的就加上相应的f,不是两个同时成立或者不成立 const int mod = 1000000007;
*/
const int mod=1000000007;
void dabiao()
{
    memset(f,0,sizeof f) ;
    f[0]=  1,f[1]=1 ,f[2] = 2 ;
    int flag= -1;
    for(int i=3 ; i<=100005;i++){
        for(int j=1 ; ;j++){
            if(j % 2) flag =1;
            else flag=-1;
            int t = (i - j*(3*j-1)/2) ;
            int ct = (i-j*(3*j+1)/2);
            if(t < 0&& ct<0 ) break;
            if(t>=0){
                f[i]=(f[i] + flag*f[t]) % mod;
            }
            if(ct>=0){
                f[i]=(f[i]+flag*f[ct]) % mod ;
            }
        }
        f[i] = (f[i] + mod)% mod ;
     }
}
int main()
{
    dabiao() ;
    int t;
    scanf("%d",&t) ;
    while(t--){
        int n;
        scanf("%d",&n);
        cout<<f[n]<<endl;

    }
    return 0;
}

hdu 4658 限制每个数字出现的次数不能超过 m

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
long long f[100010] ;
//:f[n]=∑(-1)^(k-1)*(f[n-k*(3*k-1)/2]+f[n-k*(3*k+1)/2])
/*
其中n-k*(3*k-1)/2>=0,n-k*(3*k+1)/2>=0;

        注意两个条件要分开判断,有大于0的就加上相应的f,不是两个同时成立或者不成立 const int mod = 1000000007;
*/
const int mod=1000000007;
void dabiao()
{
    memset(f,0,sizeof f) ;
    f[0]=  1,f[1]=1 ,f[2] = 2 ;
    int flag= -1;
    for(int i=3 ; i<=100005;i++){
        for(int j=1 ; ;j++){
            if(j % 2) flag =1;
            else flag=-1;
            int t = (i - j*(3*j-1)/2) ;
            int ct = (i-j*(3*j+1)/2);
            if(t < 0&& ct<0 ) break;
            if(t>=0){
                f[i]=(f[i] + flag*f[t]) % mod;
            }
            if(ct>=0){
                f[i]=(f[i]+flag*f[ct]) % mod ;
            }
        }
        f[i] = (f[i] + mod)% mod ;
     }
}
long long calcu(int n,int m)
{
    int flag = -1;
    long long ans = f[n] ;
    for(int i=1;;i++){
        int t =  (i*(3*i-1)/2) ;
        int ct = (i*(3*i+1)/2);
        if(t*m<= n){
            ans = (ans+ flag*f[n-m*t]) %mod ;
        }
        else break;
        if(ct*m<=n){
            ans = (ans+flag*f[n-m*ct]) % mod;
        }
        else break;
        flag*=-1;
    }
    ans= (ans + mod) %mod;
    return ans;
}
int main()
{
    dabiao() ;
    int t;
    scanf("%d",&t) ;
    while(t--){
        int n , m;
        scanf("%d%d",&n,&m);
        cout<<calcu(n,m)<<endl;

    }
    return 0;
}
时间: 2024-10-10 01:14:25

整数拆分学习的相关文章

整数拆分

将一个整数N拆分成n个连续自然数的和.例如: 15 = 1+2+3+4+5 15 = 4+5+6 15 = 7+8 实现一个函数,打印所有可能,并且统计有多少种方法? 分析过程如下. 对于一个数N, 2个自然数相加:m+(m+1)                                                                                                                  =2m+1 3个自然数相加:(m-1)+m

Pollard-Rho大整数拆分模板

随机拆分,简直机智. 关于过程可以看http://wenku.baidu.com/link?url=JPlP8watmyGVDdjgiLpcytC0lazh4Leg3s53WIx1_Pp_Y6DJTC8QkZZqmiDIxvgFePUzFJ1KF1G5xVVAoUZpxdw9GN-S46eVeiJ6Q-zXdei 看完后,觉得随机生成数然后和n计算gcd,可以将随机的次数根号一下.思想很叼. 对于里面说的birthday trick,在执行次数上我怎么看都只能减一半.只是把平均分布,变成了靠近0

poj 1221 UNIMODAL PALINDROMIC DECOMPOSITIONS 整数拆分

题意: 给一个数n,求有多少种和为n的单峰先增对称序列,比如当n=5时结果为3:(5), (1 3 1), (1 1 1 1 1). 分析: 转化为求类似整数拆分问题,f(i,j)的意义是把i进行拆分,最大数小于等于j的方法数. 代码: //poj 1221 //sep9 #include <iostream> using namespace std; const int maxN=300; __int64 a[maxN+10][maxN+10]; __int64 f(int m,int n)

poj 2229 完全背包变形(求解整数拆分问题)

整数拆分问题:给定一个正整数n,将n拆分为若干数字的和,问有多少种方法? 此题为整数拆分问题的子问题,拆分出的数字要求是2的幂次. 定义dp[i][k]表示枚举到第k个数字时数字i的拆分方案数. 则有状态转移方程: dp[i][k] = dp[i][k - 1] + dp[i - num[k]][k]; 熟悉完全背包的朋友可以看出,这个方程和完全背包的状态转移方程如出一辙,第二维可以省去,只要将i从小到大枚举即可. 1 #include <iostream> 2 #include <cs

poj 3014 Cake Pieces and Plates 整数拆分

题意: 将m拆成n个数,允许某个数为0,求拆分方案数. 分析: 裸的整数拆分,设h(m,n)表示将m拆成n个数,允许某数为0的方案数,递推方程见代码.很有意思的是,参考上一篇写poj1221的博文中,设f(m,n)表示将m进行任意份数不允许有0的整数拆分,且最大元素小于等于m的方案数,则h(m,n)==f(m,n)....求解此等式意义... 代码: //poj 3014 //sep9 #include <iostream> using namespace std; const int max

LightOJ 1336 Sigma Function(数论 整数拆分推论)

--->题意:给一个函数的定义,F(n)代表n的所有约数之和,并且给出了整数拆分公式以及F(n)的计算方法,对于一个给出的N让我们求1 - N之间有多少个数满足F(x)为偶数的情况,输出这个数. --->分析:来考虑F(x)为奇数的情况,给据题目中给我们的公式,,如果F(x)为奇数,那么这个多项式里面的任何一项都必须是奇数,可以知道p = 2时,        p^e - 1肯定是奇数,如果p != 2,当且仅当e为偶数的时候,此项为奇数,证明如下: 原式变形为[ p^(e+1) -p + (

整数拆分问题的四种解法【转载】

http://blog.csdn.net/u011889952/article/details/44813593 整数拆分问题的四种解法 原创 2015年04月01日 21:17:09 标签: 算法 / 母函数定理 / 五边形数定理 / acm / 动态规划 整数划分问题是算法中的一个经典命题之一 所谓整数划分,是指把一个正整数n写成如下形式: n=m1+m2+m3+....+mi;(其中mi为正整数,并且1<=mi<=n),则{m1,m2,m3,....,mi}为n的一个划分. 如果{m1,

【转载转载转载!】整数拆分问题的四种解法--尼奥普兰

整数拆分问题的四种解法 原创 2015年04月01日 21:17:09 标签: 算法 / 母函数定理 / 五边形数定理 / acm / 动态规划 整数划分问题是算法中的一个经典命题之一 所谓整数划分,是指把一个正整数n写成如下形式: n=m1+m2+m3+....+mi;(其中mi为正整数,并且1<=mi<=n),则{m1,m2,m3,....,mi}为n的一个划分. 如果{m1,m2,m3,....,mi}中的最大值不超过m,即max{m1,m2,m3,....,mi} <= m,则称

LeetCode 343.整数拆分 - JavaScript

题目描述:给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积. 题目分析 题目中"n 至少可以拆分为两个正整数的和",这个条件说明了 n 是大于 1 的整数. 对 7 来说,可以拆成 3+4,最大乘积是 12. 对 8 来说,可以拆成 3+3+2,最大乘积是 18. 解法 1: 动态规划 状态数组dp[i]表示:数字 i 拆分为至少两个正整数之和的最大乘积.为了方便计算,dp 的长度是 n + 1,值初始化为 1. 显然dp[2]等于