luogu4127 同类分布

传送门

数位DP,枚举数位和,然后用 f [ p o s ] [ r e s ] [ n o w ] [ l i m i t ] f[pos][res][now][limit] f[pos][res][now][limit]记录还需要填 p o s pos pos个数,当前余数为 r e s res res,当前数位和为 n o w now now,是否有限制的方案数。
注意每枚举一次 s u m sum sum都要把 f f f清空。因为 s u m sum sum一直在变。

一开始不小心把 f f f数组中 n o w now now写成 s u m sum sum了。谢谢 G S J GSJ GSJ神仙。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[20],sum;ll l,r;
ll f[20][165][165][2];
inline ll dp(int pos,int res,int now,bool limit,ll ans=0){
    if(now>sum) return 0;
    if(!pos) return (now==sum)&&(!res);
    if(~f[pos][res][now][limit]) return f[pos][res][now][limit];
    int up=limit?a[pos]:9;
    for(int i=0;i<=up;++i)
        ans+=dp(pos-1,(res*10+i)%sum,now+i,limit&&(i==up));
	return f[pos][res][now][limit]=ans;
}
inline ll calc(ll x,int pos=0,ll tot=0){
    while(x) a[++pos]=x%10,x/=10;
    for(sum=1;sum<=(9*pos);++sum){
    	memset(f,-1,sizeof(f));
    	tot+=dp(pos,0,0,true);
    }return tot;
}
int main(){
    memset(f,-1,sizeof(f));
    cin>>l>>r;cout<<(calc(r)-calc(l-1));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值