bzoj 4521 [Cqoi2016]手机号码

数位DP。
设f[pos][p2][p1][con][bj8][bj4]表示第pos位,前两个数为p2,p1,con表示是否已经有三个连续出现的数字,bj8表示8是否已经出现,bj4同理。在这种情况下的方案数。

用记忆化搜索比较方便。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
LL a[20],f[20][15][15][2][2][2],vst[20][15][15][2][2][2];
LL DFS(LL pos,LL op,LL p2,LL p1,LL con,LL bj8,LL bj4)
{   if(bj8&&bj4)return 0;
    if(pos==0)return con;
    if(!op&&vst[pos][p2][p1][con][bj8][bj4])return f[pos][p2][p1][con][bj8][bj4];
    LL i,lim=op?a[pos]:9,ret=0;
    for(i=(pos==a[0]);i<=lim;i++)ret+=DFS(pos-1,op&&(i==lim),p1,i,con||(p2==p1&&p1==i),bj8||(i==8),bj4||(i==4));
    if(!op)
      {vst[pos][p2][p1][con][bj8][bj4]=1;
       f[pos][p2][p1][con][bj8][bj4]=ret;
      }
    return ret;
}
LL Cal(LL x)
{   a[0]=0;
    while(x){a[++a[0]]=x%10;x/=10;}
    return DFS(a[0],1,0,0,0,0,0);
}
int main()
{   LL L,R;
    cin>>L>>R;
    if(L==10000000000LL)cout<<Cal(R);
    else cout<<Cal(R)-Cal(L-1);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值