算法设计与分析-10302 整数的特殊划分

 当问题是方案数时,一般都是动态规划问题。

基于递归分治的思想,如何将n的划分,下降为小于n的划分。需要注意到每一种划分中有两个数字比较重要,最小值和最大值。思考如何递归时必然从这两个值中某一个入手。

解题思路:从最大值入手。设定dp(i,j)为整数i且最大值为2^{j}的划分方案数。那么可以递归向下得到dp(i,j)的方案数是:

动规方程为:

dp(i,j)=\sum_{k=0}^{k<=j}dp(i-2^{j},k)

因为dp(i,j)定义的是i最大值一定是2^j的方案数,所以要求整数n的全部划分方案数时,其结果为dp(n,1)+dp(n,2)+dp(n,4)+...........的总和。

题目不能使用递归,复杂度太高,采用递推的方法,用二维数组表示dp[i][j],按从小到大次序顺序推出所有解。算法复杂度为n*(\log_{2}n)^{2}

下面代码中lg数组用于求2的对数值,1<<j属于移位操作,将1左移j位得到的结果是2^{j}

(友情提示:本代码已开启防抄袭模式,请勿复制粘贴)

#include <iostream>//ASI
typedef long long ll;
using namespace std;
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int i,j,k,n,dp[10005][21]= {0},lg[100005],sum=0;
    cin>>n;
    lg[0]=-1;/**<一种以2为底对数处理技巧*/
    for(i=1; i<=n; i++)/**< 可以快速通过数组lg[i]得到以2为底i的对数 */
        lg[i]=lg[i/2]+1;
    for(i=1; i<=n; i++)
    {  
        for(j=0; j<=lg[i]; j++) /**< dp[i][j]表示i的一个加法序列,且序列中最大值为2的j次幂 */
        {
            if(1<<j==i) /**< 特殊处理,当i就是2的整数次幂时,其自身也是一种方案。如8=8 */
                dp[i][j]=1;
            for(k=0; k<=j; k++) /**<dp[i][j] 最大值是2的j幂,那么拿走最大值,剩下i-(1<<j),其最大值只要小于2的j幂即可 */
                dp[i][j]=(dp[i][j]+dp[i-(1<<j)][k])%100000000;
        }
    }
    for(i=0;i<=lg[n];i++) /**< n最大值为1,2,4,8....lg[n],全部的方案数总和即为答案 */
        sum =(sum+dp[n][i])%100000000;
    cout<<sum;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值