您的位置:首页 > 其它

hdu2089 不要62--经典数位DP

2017-01-12 09:57 423 查看
       一道十分经典的数位DP的题目。

       dp[i][j]表示最高位是数字i,连同最高位在内共有j位。注意边界的初始化。

        接下来就是区间划分,特殊情况处理.....对了,如果不知道自己的方法是否正确,可以写一个测试函数:

bool check(int n){ //判断n是否符合条件
int a[20];
int c=0;
while(n>0){
a[c++]=n%10;
n/=10;
}
for(int i=0;i<c;++i) if(a[i]==4) return false;
for(int i=0;i<c-1;++i){
if(a[i]*10+a[i+1]==26) return false;
}
return true;
}
inline int solve(int n){ //可以求得0~n之间有多少符合条件的数
int ans=0;
for(int i=0;i<=n;++i)
if(check(i)) ++ans;
return ans;
}

AC代码:

#include<cstdio>
#include<cstring>
#include<cmath>
const int maxn=20;
int dp[10][maxn];
void deal(){
memset(dp,0,sizeof(dp));
//初始化边界
for(int i=0;i<10;++i){
if(i==4) continue;
else dp[i][1]=1;
}
for(int i=2;i<10;++i){ //length
for(int j=0;j<10;++j){
if(j==4) continue;
for(int k=0;k<10;++k){
dp[j][i]+=dp[k][i-1];
}
}
dp[6][i]-=dp[2][i-1];
}
}
inline int solve(int pre,int n,int len){
if(pre==62||pre%10==4||pre/10==4) return 0;
if(len==1){
int ans=0;
for(int i=0;i<=n;++i)
if(i==4) continue;
else ++ans;
if(pre%10==6&&n>=2) --ans;
return ans;
}
int ans=0;
int m=(int)pow(10,len-1);
int up=n/m;
for(int i=0;i<up;++i){
ans+=dp[i][len];
}
if(pre%10==6&&up>2) ans-=dp[2][len];
return ans+solve(pre%10*10+up,n%m,len-1);
}
inline int getlen(int n){
if(n==0) return 1;
int c=0;
while(n>0){
n/=10;
++c;
}
return c;
}
int main(){
deal();
int l,r;
while(scanf("%d%d",&l,&r)!=EOF&&l&&r){
int a=solve(0,r,getlen(r));
int b=solve(0,l-1,getlen(l-1));
//printf("%d-%d=%d\n",a,b,a-b);
printf("%d\n",a-b);
}
return 0;
}

如有不当之处欢迎指出!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: