zoukankan      html  css  js  c++  java
  • 51nod 1043 幸运号码(数位dp

    1个长度为2N的数,如果左边N个数的和 = 右边N个数的和,那么就是一个幸运号码。
    例如:99、1230、123312是幸运号码。
    给出一个N,求长度为2N的幸运号码的数量。由于数量很大,输出数量 Mod 10^9 + 7的结果即可。
    Input
    输入N(1<= N <= 1000)
    Output
    输出幸运号码的数量 Mod 10^9 + 7
    Input示例
    1
    Output示例
    9

    看的网上的题解 但是觉得他们写的还是有问题的  

    用dp[i][j]表示i个数的和为j的总数,这里面是包括0开头的情形,有dp[i][j]=dp[i-1][j-k](k从0到9)。

    很好想,i个数组成总和为j的数量就来自于i-1个数 里面能 在最前面加0到9的数字使得加完之后和为j。

    这里面包含了0开头的,把0去掉的方法就是dp[i][j]-dp[i-1][j]。

    dp[i-1][j]就代表了在i个数中,开头为0的个数,减去就是i个数中开头不为0的个数。

    原因很明显,i个数和为j与i-1个数和为j,就差了一个位置为0。而这一个位置因为一开始咱们的想法就是在最前面加的数字,所以这个位置就差在了最前面的位置上

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod = 1e9+7;
    int dp[1010][10000];// dp[i][j] 为i个数 和为j的情况
    
    int main()
    {
        int n;
        scanf("%d",&n);
        dp[0][0] = 1;//这里明明是网上题解有错误 他们都写的是dp[0][1] = 1
        //明明他们是在凑样例的感觉  应该是0个数 凑成0的情况是1
        for(int i=0;i<=9;i++)
            dp[1][i] = 1;
        for(int i=2;i<=n;i++)
        {
            for(int j=0;j<=9*i;j++)
            {
                int sum = 0;
                for(int k=0;k<=9;k++)
                {
                    if(j >=k)
                        sum = (sum + dp[i-1][j-k])%mod;
                    else
                        break;
                }
                dp[i][j] = sum;
            }
        }
        ll ans = 0;
        for(int i=0;i<=9*n;i++)
            ans = (ans + (ll)dp[n][i] * (dp[n][i]-dp[n-1][i]))%mod;//这里单独 (ll)dp[n][i] * (dp[n][i]-dp[n-1][i]) 会超精度
        printf("%lld
    ",ans);
    }

    下面是用滚动数组内存优化过的 用的now 和pre   (强行装逼, 不过倒腾了半个小时  now 和 pre 的关系

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod = 1e9+7;
    
    int dp[2][10000];
    
    int main ()
    {
        int n;
        scanf("%d",&n);
        int now = 0,pre = 1;
        dp[0][0] = 1;
        swap(now,pre);
        for(int i=0;i<=9;i++)
            dp[now][i] = 1;
        swap(now,pre);
        for(int i=2;i<=n;i++)
        {
            for(int j=0;j<=9*n;j++)
            {
                ll sum =0;
                for(int k=0;k<=9;k++)
                {
                    if(j>=k)
                        sum = (sum+dp[pre][j-k])%mod;
                    else
                        break;
                }
                dp[now][j] = sum;
            }
            swap(now,pre);
        }
        ll ans = 0;
        for(int i=0;i<=9*n;i++)
        {
            ans = (ans + (ll)dp[pre][i]*(dp[pre][i] - dp[now][i]))%mod;
        }
        printf("%lld
    ",ans);
    }

    别人的代码  (随便看看就好 主要是滚动优化 可以学一下(n&1)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define maxn 10005
    #define Mod  1000000007
    ll dp[2][maxn];
    int main()
    {
        ll n,m,i,j,k,sum,ans=0;
        scanf("%lld",&n);
        dp[0][0]=1;//这里是0
        for(i=0;i<=9;i++)
        dp[1][i]=1;
        for(i=2;i<=n;i++)
        {
            for(j=0;j<=n*9;j++)
            {
               sum=0;
               for(k=0;k<=9;k++)
               {
                    if(j>=k)
                    sum=(sum+dp[(i-1)%2][j-k])%Mod;
                    else
                    dp[i%2][j]=0;
               }
               dp[i%2][j]=sum;
            }
        }
        for(i=0;i<=9*n;i++)
        ans=(ans+dp[n%2][i]*(dp[n%2][i]-dp[(n-1)%2][i])%Mod)%Mod;
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    MyEclipse 2014 破解图文详细教程
    Eclipse构建Maven项目
    Eclipse构建Maven项目
    Spring--环境配置
    Spring--环境配置
    Sencha Touch2 -- 11.1:定义具有关联关系的模型
    Sencha Touch2 -- 11.1:定义具有关联关系的模型
    Android百度定位API的使用
    Android百度定位API的使用
    Java基础学习总结(64)——Java内存管理
  • 原文地址:https://www.cnblogs.com/Draymonder/p/7390200.html
Copyright © 2011-2022 走看看