您的位置:首页 > 其它

bzoj1833: [ZJOI2010]count 数字计数(数位dp)

2017-05-06 00:24 399 查看

  学习了一波记忆化数位dp后写这题...我好像写的都跟大家的不一样???跑的还挺快的???(其实全世界一样都是0ms...)

  题目大意:求[a,b]中0~9分别出现几次。(a,b<=10^12)

  dp[pos][num][sum]表示前pos位,求num出现几次,这个数前pos位num已经出现sum次,前导零也很好处理,套记忆化模板就行了。

  (太久没写博客了水一篇...(雾

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#define ll long long
using namespace std;
ll dp[20][20][20],a[20],l,r;
void read(ll &k)
{
k=0;ll f=1;char c=getchar();
while(c>'9'||c<'0')c=='-'&&(f=-1),c=getchar();
while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
k*=f;
}
ll dfs(int pos,int num,ll sum,bool lead,bool limit)
{
if(pos==0)return sum;
if(!limit && !lead && dp[pos][num][sum]!=-1)return dp[pos][num][sum];
int up=limit?a[pos]:9;
ll ans=0;
if(!lead||pos==1)ans+=dfs(pos-1,num,sum+(num==0),0,limit && a[pos]==0);
else ans+=dfs(pos-1,num,sum,1,limit && a[pos]==0);
for(int i=1;i<=up;i++)
ans+=dfs(pos-1,num,sum+(num==i),0,limit && a[pos]==i);
if(!limit && !lead)dp[pos][num][sum]=ans;
return ans;
}
ll solve(ll x,int num)
{
if(x<0)return 0;
if(x==0)return num==0?1:0;
int pos=0;
while(x)
{
a[++pos]=x%10;
x/=10;
}
return dfs(pos,num,0,1,1);
}
int main()
{
read(l);read(r);
memset(dp,-1,sizeof(dp));
for(int i=0;i<=8;i++)
printf("%lld ",solve(r,i)-solve(l-1,i));
printf("%lld\n",solve(r,9)-solve(l-1,9));
}
View Code

 

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