[BZOJ] 1833: [ZJOI2010]count 数字计数

用DFS实现的数位dp

设当前做到第pos位,所求数字为num,出现了sum次,允许/不允许前导0,保证/未保证随意填的状态,即可DFS

坚信数位DP是不会卡时间的,慢点好写

#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;

typedef long long ll;

inline ll rd(){
  ll ret=0ll,f=1ll;char c;
  while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
  while(isdigit(c))ret=ret*10ll+c-'0',c=getchar();
  return ret*f;
}

ll L,R;
ll f[20][20][20];
int a[31];

ll dfs(int pos,int num,ll sum,int zero,int lim){
  if(pos==0)return sum;
  if(!zero&&!lim&&f[pos][num][sum]!=-1) return f[pos][num][sum];
  ll ret=0ll;
  int up=lim?a[pos]:9;
  if(!zero||pos==1)ret+=dfs(pos-1,num,sum+(num==0),0,lim&&a[pos]==0);
  else ret+=dfs(pos-1,num,sum,1,lim&&a[pos]==0);
  for(int i=1;i<=up;i++)ret+=dfs(pos-1,num,sum+(num==i),0,lim&&a[pos]==i);
  if(!zero&&!lim)f[pos][num][sum]=ret;
  return ret;
}

ll solve(ll x,int num){
  if(x<0) return 0;
  if(x==0) return num==0;
  int top=0;
  while(x){
    a[++top]=x%10;
    x/=10;
  }
  return dfs(top,num,0,1,1);
}

int main(){
  L=rd();R=rd();
  memset(f,-1,sizeof(f));
  for(int i=0;i<=9;i++)printf("%lld ",solve(R,i)-solve(L-1,i));
  return 0;
}
posted @ 2018-09-29 20:49  GhostCai  阅读(137)  评论(0编辑  收藏  举报