zoukankan      html  css  js  c++  java
  • 整数划分问题模型

    整数划分问题模型

    问题一: 求把n划分成k个正整数的方案数?

    暴力dp:(暴力dp要做到不重不漏)
    设dp[i][j][sum]表示前i个正整数,选了j个数,和为sum的方案数,答案是:dp[n][k][n]
    本质:完全背包
    复杂度:O(n*k*n)
    正解:
    直接设dp[i][j]表示把i划分成j个数的方案数
    则dp[i][j]=dp[i-j][j]+dp[i-1][j-1](可从数形结合或者抽屉原理的方面来考虑)
    

    问题二:求把n划分成互不相同k个正整数的方案数?

    暴力dp:
    设dp[i][j][sum]表示前i个正整数,选了j个数,和为sum的方案数,答案是:dp[n][k][n]
    本质:0/1背包
    复杂度:O(n*k*n)
    正解:
    直接设dp[i][j]表示把i划分成j个数的方案数
    则dp[i][j]=dp[i-j][j]+dp[i-j][j-1](可从数形结合或者抽屉原理的方面来考虑)
    

    问题三:求把n划分成k个不大于m的互不相同正整数的方案数?

    直接上正解:
    设dp[i][j]表示把i划分成j个数的方案数
    dp[i][j]=dp[i-j][j]+dp[i-j][j-1]-dp[i-(m+1)][j-1(可从数形结合或者抽屉原理的方面来考虑)
    

    问题四:求把n划分成k个奇数的方案数?

    引用zhhx的:
    可重复数字纯奇纯偶划分
    g[i][j]:将i划分为j个偶数的方案数
    f[i][j]:将i划分为j个奇数的方案数
    g[i][j] = f[i - j][j] f[i][j] = f[i - 1][j - 1] + g[i - j][j];
    不可重复也是一样的。
    

    例题:

    洛谷P1025 数的划分

    问题一“把n划分成k个正整数的方案数”的弱化版,好像是暴力dp就能过的那种,但可以拿来练手,判判边界之类的(水经验

    #include <iostream>
    #include <cstdio>
    using namespace std;
    int f[210][10];
    int n,k;
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)f[i][1]=1;
        for(int i=1;i<=k;i++)f[i][i]=1;
        for(int i=2;i<=n;i++)
        {
            for(int j=2;j<=k&&j<i;j++)
            {
                f[i][j]=f[i-1][j-1]+f[i-j][j];
            }
        }
        printf("%d",f[n][k]);
        return 0;
    }
    

    洛谷P4104 [HEOI2014]平衡

    问题可转化为从1~2n+1中选出k个整数,使得这k个整数和为k*(n+1)
    其实就是问题三“把n划分成k个不大于m的互不相同正整数的方案数”的模板
    在原问题中应该是把k*(n+1)划分成k个不大于2n+1的互不相同的正整数的方案数
    复杂度:O(n*k*k)
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int n,k,p;
    int f[100100*2][15];
    int main()
    {
        int T;scanf("%d",&T);
        while(T--)
        {
        memset(f,0,sizeof(f));
        scanf("%d%d%d",&n,&k,&p);
        for(int i=1;i<=(2*n+1);i++)f[i][1]=1;
        for(int i=2;i<=k*(n+1);i++)
        {
            for(int j=2;j<=k&&j<i;j++)
            {
                int m=2*n+1;
                if(i>(m+1))
                f[i][j]=f[i-j][j-1]%p+f[i-j][j]%p-f[i-(m+1)][j-1]%p;
                else f[i][j]=f[i-j][j-1]%p+f[i-j][j]%p;
            }
        }
        printf("%d
    ",(f[k*(n+1)][k]%p+p)%p);
        }
        return 0;
    }
    
  • 相关阅读:
    光场显微成像----整理
    清华大学自动化系友论坛——光电智能计算:笔记
    大创记录——Day3.12
    2.17UI bug修复
    beta阶段UI界面改进
    关于UI设计的心得体会-alpha和beta交界期间
    1.30进度
    2018.1.28进度更新
    心·迹 项目简介
    项目组成员介绍
  • 原文地址:https://www.cnblogs.com/Akaina/p/11259344.html
Copyright © 2011-2022 走看看