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;
}

 

posted @ 2018-09-19 10:26  MT_LI  阅读(125)  评论(0编辑  收藏  举报