BZOJ 1799: [Ahoi2009]self 同类分布
Description
给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。
Sample Input
10 19
Sample Output
3
HINT
【约束条件】1 ≤ a ≤ b ≤ 10^18
水题卡我半小时我就是个制杖
这DP套路太明显了吧,本来开五维的数据太大发现可以消掉一维
f[p][i][j][k]:p=1表示顶到上界,只能选到上界,不然到min(9,数字和),0则相反
处理到第i位,数字和为j,前i位对于当前我们枚举的数字和取模结果为k
然后瞎jb转移即可
//MT_LI #include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; typedef long long ll; ll f[2][21][250][250];int v[2][21][250][250]; int mod,tim,a[21],cnt; ll dp(int p,int i,int j,int k) { if(!(p|i|j|k)||(p==1&&(i|j|k)==0))return 1; if(v[p][i][j][k]==tim)return f[p][i][j][k]; v[p][i][j][k]=tim;ll sum=0ll; int l=max(0,j-(i-1)*9),r=min(j,(p)?9:a[i]); for(int x=l;x<=r;x++)sum+=dp(p|(x<a[i]),i-1,j-x,(k*10+x)%mod); return f[p][i][j][k]=sum; } ll solve(ll x) { ll sum=0ll;cnt=0; while(x)a[++cnt]=x%10,x/=10; for(mod=1;mod<=9*cnt;mod++) tim++,sum+=dp(0,cnt,mod,0); return sum; } int main() { ll l,r; scanf("%lld%lld",&l,&r); printf("%lld\n",solve(r)-solve(l-1)); return 0; }
The deepest love I think,later than apart,I will live as you like