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);
    }
  • 相关阅读:
    Rotation Kinematics
    离职 mark
    PnP 问题方程怎么列?
    DSO windowed optimization 代码 (4)
    Adjoint of SE(3)
    IMU 预积分推导
    DSO windowed optimization 代码 (3)
    DSO windowed optimization 代码 (2)
    OKVIS 代码框架
    DSO windowed optimization 代码 (1)
  • 原文地址:https://www.cnblogs.com/Draymonder/p/7390200.html
Copyright © 2011-2022 走看看