• ZOJ 1163


    数论+DP

    数的划分

    dp(k, n),表示数 n 的最小被加数不小于 k 的分划的个数。对于给定的 k 值,dp(k, n) 正好分为以下两类:

    1最小被加数等于 k
    2最小被加数大于 k

    满足第一个条件的分划的个数是 dp(k + 1, n − k)。 这是因为,让我们想象数 n − k 的最小被加数大于 k 的分划,然后将 "+ k" 附加每一个分划后面,就得到数 n 的最小被加数等于 k 的分划。以 n = 8, k = 1 为例,数 7 的最小被加数大于 1 的分划是 7、5 + 2 和 4 + 3,即 dp(k + 1, n − k) = dp(2, 7) = 3。然后,将 "+ 1" 附加在这 3 个分划后面,就得到数 8 的最小被加数等于 1 的分划:7 + 1、5 + 2 + 1 和 4 + 3 + 1。

    满足第二个条件的分划的个数是 q(k + 1, n) 。以 n = 8, k = 1 为例,数 8 的最小被加数大于 1 的分划是 8、6 + 2 和 5 + 3,即 dpk + 1, n) = dp(2, 8) = 3。

    也就是说,dp(1, 8) = dp(2, 8) + dp(2, 7)。因此:

            dp(k, n) = 0  如果 k > n
            dp(k, n) = 1  如果 k = n
            dp(k, n) = dp(k+1, n) + dp(k + 1, n-k);

    #include <iostream>
    using namespace std;
    #define max 505
    typedef long long ll;
    ll dp[max][max];
    void getdp(){
        for(int i=1;i<=max;i++)
        {
            dp[i][i]=1;
            for(int j=i+1;j<max;j++)
            dp[i][j]=0;
        }
        for(int i=2;i<max;i++)
            for(int j=i-1;j>=1;j--)
                dp[i][j]=dp[i][j+1]+dp[i-j][j+1];
    }
    int main(){
        int t;
        getdp();
        while(cin>>t){
                if(!t)break;
            cout<<dp[t][1]-1<<endl;
        }
        return 0;}

  • 相关阅读:
    RramSim2
    DiskSim
    FTL2
    Durable NAND flash memory management
    node系列:全局与本地
    CSS系列:less备忘
    Sql Server 2008:调试
    JavaScript系列:再巩固-原型链
    移动端 :meta标签1万个作用
    Asp.Net:Repeater 详情 备用
  • 原文地址:https://www.cnblogs.com/Mr-Xu-JH/p/3867239.html
Copyright © 2020-2023  润新知