牛客训练三:处女座和小姐姐(三)(数位dp)
题目链接:传送门
思路:数位dp的记忆化搜索模板
从高位向低位枚举,逐位确定每一位的6的个数,dp[i][s]表示处理到第i条边,状态为s时的数字的个数。
注意,要使用long long类型。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long LL; LL a[50],dp[50][50],x,y; LL dfs(LL pos,LL statue,bool done) //pos表示位数,statue表示当前的状态(不同的题目改变不同的状态,本题只表示前i位中是否有6),done表示是否处理 { if(pos==-1) return statue; //位数超限 if(!done&&~dp[pos][statue]) return dp[pos][statue]; //此状态已存在,直接返回已有的值即可 LL i,ans=0,len=(done?a[pos]:9); //len用于找出当前位要处理的个数,如果未标记(done=0)就是0-9,否则0-a[pos]。 for(i=0;i<=len;i++){ ans+=dfs(pos-1,statue||i==6,done&&a[pos]==i); //ans用于求前i位的6的数字之和 } return (!done)?(dp[pos][statue]=ans):ans; //优化,记录已有的数据。 } LL solve(LL x) { LL pos=0; memset(dp,-1,sizeof(dp)); while(x){ a[pos++]=x%10; //预处理 x/=10; } return dfs(pos-1,0,true); } int main(void) { while(~scanf("%lld%lld",&x,&y)){ printf("%lld\n",solve(y)-solve(x-1)); } return 0; }