bzoj 4521 [ Cqoi 2016 ] 手机号码 —— 数位DP

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4521

数位DP,记录好多维状态;

写了半天,复杂得写不下去了,于是参考一下TJ...

练习简洁地写出数位DP。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
ll l,r,f[15][15][3][3][3][3],a[15],ans;//i,数字,限制,二连,三连, 4/8 
int tmp[15];
ll solve(ll mx)
{
    ll tt=mx;
    for(int i=1;i<=11;i++)a[i]=tt%10,tt/=10;
    memset(f,0,sizeof f);
    f[12][0][1][0][0][0]=1;//1 表示有限制 
    for(int i=11;i;i--)
        for(int j=0;j<=9;j++)//i+1
            for(int t1=0;t1<=1;t1++)//限制 
                for(int t2=0;t2<=1;t2++)//二连 
                    for(int t3=0;t3<=1;t3++)//三连 
                        for(int t4=0;t4<=2;t4++)// 4/8 
                            if(f[i+1][j][t1][t2][t3][t4])
                            {
                                for(int k=0;k<=(t1?a[i]:9);k++)
                                {
                                    if((t4==1&&k==8)||(t4==2&&k==4))continue;
                                    f[i][k][t1&&k==a[i]][k==j][t3|(t2&&k==j)][t4|tmp[k]]+=
                                    f[i+1][j][t1][t2][t3][t4];
                                }
                            }
    ll ans=0;
    for(int j=0;j<=9;j++)
        for(int t1=0;t1<=1;t1++)
            for(int t2=0;t2<=1;t2++)
                for(int t4=0;t4<=2;t4++)
                    ans+=f[1][j][t1][t2][1][t4];
    return ans;
}
int main()
{
    scanf("%lld%lld",&l,&r);
    tmp[4]=1; tmp[8]=2;
    printf("%lld\n",solve(r)-solve(l-1));
    return 0;
}

 

posted @ 2018-07-22 15:51  Zinn  阅读(200)  评论(0编辑  收藏  举报