[ZJOI2010]數字計數,數位Dp
阿新 • • 發佈:2018-11-02
正題
這題看上去就像數位Dp.
對於每一個數,我們進行數位Dp。
還是類似於差分,用y的答案減去x-1的答案就可以了。
對於每個子問題,我們求解,用tf來記錄前面是否“滿”,用all記錄前面是否都是0.
如果前面滿了,我們列舉的end就是當前這一位的值,否則就是9.
如果這一位以及前面有不是0的位,那麼這一位就有可能能取到答案,前面以及這一位滿了,那麼就是後一位的權值+1,否則就可以取10的冪次方。
這樣每次Dp都記憶化一下就可以了。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; long long x,y; long long solve[100]; long long val[100]; long long ci[100]; long long g[100]; long long Dp(int pos,int tf,int k,int all){ if(pos==0) return 0; if(!tf && !all && solve[pos]!=-1) return solve[pos]; long long res=0; int end=tf?val[pos]:9; for(int i=0;i<=end;i++) { res+=Dp(pos-1,tf&&i==end,k,all&&i==0); if(!(all && i==0) && i==k) res+=((i==end&&tf)?g[pos-1]+1:ci[pos-1]); } if(!all && !tf) solve[pos]=res; return res; } long long gett(long long v,int k){ memset(solve,-1,sizeof(solve)); int len=0; while(v!=0){ val[++len]=v%10; v/=10; g[len]=g[len-1]+val[len]*ci[len-1]; } return Dp(len,1,k,1); } int main(){ ci[0]=1; for(int i=1;i<=15;i++) ci[i]=ci[i-1]*10; long long tot=0; scanf("%lld %lld",&x,&y); x--; for(int i=0;i<=9;i++) printf("%lld ",gett(y,i)-gett(x,i)); }