• 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);
    }
  • 相关阅读:
    错误代码 0x800700b7 配置错误定义了重复的“system.web.extensions/scripting/scriptResourceHandler”节
    字符型设备驱动程序-first-printf以及点亮LED灯(一)
    翻译 TI SerialBLEbridge V 1.4.1
    lwip TCP client & FreeRTOS 打开TCP 的 保活机制 LWIP_TCP_KEEPALIVE==1
    lwip TCP client 客户端 & FreeRTOS
    CC2540 OSAL 学习其中原理,以及 给任务 添加 一个事件(定时发送串口消息)
    跟我一起学Linux-线程创建,类似FreeRTOS创建任务
    用 S5PV210 学习 Linux (三) SD卡下载
    用 S5PV210 学习 Linux (二) 刷机(二)
    用 S5PV210 学习 Linux (一) 刷机(一)
  • 原文地址:https://www.cnblogs.com/Draymonder/p/7390200.html
Copyright © 2020-2023  润新知