HDU:4249 A Famous Equation(数位DP)

题意:给一个表达式形如a+b=c,其中一些数字为?,问使表达式成立有多少种情况。

思路:不太容易发现是一道数位DP。比较容易建立状态转移方程,dp[i][j][k][l]表示j(0表示不进位,1表示进位)使a的第i位为k,b的第i位为l的情况个数,这样可以计算得c的第i位。用线性时间枚举位数,10^2枚举过去状态,10^2枚举现在状态建立转移即可。最后累加求和。注意前导零的问题。给一组数据??+??=???,答案是4860。注意如0?此类情况转移的状态是无效的,因此它的状态直接置0即可。

#include <iostream>
#include <string>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <map>
#include <cmath>
#include <stack>
#include <algorithm>
using namespace std;
typedef long long LL ;
LL dp[12][2][12][12];
int main()
{
    char s[100];
    int kase=0;
    while(scanf("%s",s)!=EOF)
    {
        printf("Case %d: ",++kase);
        char a[20],b[20],c[20];
        int l=strlen(s);
        char *p1=find(s,s+l,'+');
        *p1=0;
        strcpy(a,s);
        char *p2=find(p1+1,s+l,'=');
        *p2=0;
        strcpy(b,p1+1);
        strcpy(c,p2+1);
        int la=strlen(a),lb=strlen(b),lc=strlen(c);
        reverse(a,a+la);
        reverse(b,b+lb);
        reverse(c,c+lc);
        int p;
        for(p=la; p<lc; ++p ) a[p]='0';
        a[p]=0;
        for(p=lb; p<lc; ++p ) b[p]='0';
        b[p]=0;
        memset(dp,0,sizeof(dp));
        dp[0][0][0][0]=1;
        for(int i=1; i<=lc; ++i)
        {
            for(int ja=0; ja<10; ++ja)
            {
                for(int jb=0; jb<10; ++jb)
                {
                    for(int ka=0; ka<10; ++ka)
                    {
                        if(a[i-1]!='?'&&a[i-1]!=ka+'0') continue;
                        for(int kb=0; kb<10; ++kb)
                        {
                            if(b[i-1]!='?'&&b[i-1]!=kb+'0') continue;
                            int x,jc,kc,kx;
                            x=(ja+jb)/10;
                            jc=(ja+jb+0)%10;
                            kc=(ka+kb+x)%10;
                            if(c[i-1]=='?'||(kc+'0'==c[i-1]))
                            {
                                if((la!=1&&i==la&&ka==0)||(lb!=1&&i==lb&&kb==0))dp[i][x][ka][kb]=0;
                                else dp[i][x][ka][kb]+=dp[i-1][0][ja][jb];
                            }

                            x=(ja+jb+1)/10;
                            jc=(ja+jb+1)%10;
                            kc=(ka+kb+x)%10;
                            if(c[i-1]=='?'||(kc+'0'==c[i-1]))
                            {
                                if((la!=1&&i==la&&ka==0)||(lb!=1&&i==lb&&kb==0))dp[i][x][ka][kb]=0;
                                else dp[i][x][ka][kb]+=dp[i-1][1][ja][jb];
                            }

                        }
                    }
                }
            }
        }
        LL ans=0;
        int si=0,sj=0;
        if(la==lc&&la!=1) si=1;
        if(lb==lc&&lb!=1) sj=1;
        for(int i=si; i<=9; ++i)
            for(int j=sj; j<=9; ++j)
            {
                if((i+j+1)/10==0)
                {
                    if((i+j+1)%10!=0||lc==1)
                            ans+=dp[lc][1][i][j];
                }
                if((i+j)/10==0)
                {
                    if((i+j)%10!=0||lc==1)
                            ans+=dp[lc][0][i][j];
                }
            }

        printf("%I64d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值