幸运号码(51nod)

1个长度为2N的数,如果左边N个数的和 = 右边N个数的和,那么就是一个幸运号码。例如:99、1230、123312是幸运号码。给出一个N,求长度为2N的幸运号码的数量。由于数量很大,输出数量 Mod 10^9 + 7的结果即可。
题目解法:简单DP
设出数组dp【】【】,dp【i】【j】表示第i个数的和为j的个数
首先是最原始代码:

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string.h>
#include <vector>
typedef long long LL;
using namespace std;
const int Maxn = 1005;
int table[Maxn][Maxn*9+100];//不带0的DP
int dp[Maxn][Maxn*9+100];//带0的DP
int n;
const int mod = 1e9 + 7;
int main(){
    memset(table,0,sizeof(table));
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=9;i++){
        table[1][i] = 1;
        dp[1][i] = 1;
    }
    dp[1][0] = 1;
    for(int i=1;i<=1001;i++){
        for(int j=0;j<=9*i;j++){
            for(int k=0;k<=9;k++){
                if(table[i+1][j+k]-mod>-table[i][j])
                    table[i+1][j+k] = table[i+1][j+k]-mod+table[i][j];
                else
                    table[i+1][j+k]+=table[i][j];
                table[i+1][j+k]%=mod;
                if(dp[i+1][j+k]-mod>-table[i][j])
                    dp[i+1][j+k] = dp[i+1][j+k]-mod+dp[i][j];
                else
                    dp[i+1][j+k]+= dp[i][j];
                dp[i+1][j+k]%=mod;
            }
        }
    }
    while(~scanf("%d",&n)){
        LL sum = 0;
        int num = 0;
        for(int i=1;i<=9*n;i++){
            sum+=(LL)table[n][i]*(LL)(dp[n][i]);
            sum%=mod;
            //printf("%d. %d\n",i,table[n][i]);
        }
        printf("%lld\n",sum);
    }
    return 0;
}

这份代码问题很大,其中记录的数组有两个,显然不能设置成long long,否则会超出空间限制,那么就在计算的时候很小心,千万不能计算越界。这里说明个事情,这里是单组数据测试,如果是多组数据测试,我这份代码还是有优势的。
单组测试的有效数组就只有两个,一个带零的一个不带的,就声明两个就够了,进行其次不带零的数可以推出,例如DP【i】【j】不带零的结果就是DP【i】【j】带零的-DP【i-1】【j】带零的。
当然,下面的代码就是借鉴的大佬的了,写的非常不错。

typedef long long LL;
using namespace std;
const int Maxn = 1005;
int table[Maxn][Maxn*9+100];
int dp[Maxn][Maxn*9+100];
int n;
const int mod = 1e9 + 7;
int main(){
    memset(table,0,sizeof(table));
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=9;i++){
        table[1][i] = 1;
        dp[1][i] = 1;
    }
    dp[1][0] = 1;
    for(int i=1;i<=1001;i++){
        for(int j=0;j<=9*i;j++){
            for(int k=0;k<=9;k++){
                if(table[i+1][j+k]-mod>-table[i][j])
                    table[i+1][j+k] = table[i+1][j+k]-mod+table[i][j];
                else
                    table[i+1][j+k]+=table[i][j];
                table[i+1][j+k]%=mod;
                if(dp[i+1][j+k]-mod>-table[i][j])
                    dp[i+1][j+k] = dp[i+1][j+k]-mod+dp[i][j];
                else
                    dp[i+1][j+k]+= dp[i][j];
                dp[i+1][j+k]%=mod;
            }
        }
    }
    while(~scanf("%d",&n)){
        LL sum = 0;
        int num = 0;
        for(int i=1;i<=9*n;i++){
            sum+=(LL)dp[n][i]*(LL)(dp[n][i]-dp[n-1][i]);
            sum%=mod;
            //printf("%d. %d\n",i,table[n][i]);
        }
        printf("%lld\n",sum);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值