P4127 [AHOI2009]同类分布
题目描述
给出两个数,求出中各位数字之和能整除原数的数的个数。
Solution
发现题目有两个变量
- 数位之和
- 原数
于是必须想办法设计一个只有一种变量的数位dp,
发现唯有固定数位之和才可以在DFS中将取模作为状态方便地转移
记搜元素:
- 当前数位
- 数位之和
- 原数的模值
Code
#include<bits/stdc++.h>
#define reg register
#define pb push_back
typedef long long ll;
std::vector <int> Bt;
ll dp[19][205][205];
int mod;
ll DFS(int k, int flag, int sum_1, int sum_m){
if(sum_1 > mod) return 0;
if(k == -1){
if(!sum_m && sum_1==mod) return 1;
return 0;
}
if(!flag && ~dp[k][sum_1][sum_m]) return dp[k][sum_1][sum_m];
int end = flag?Bt[k]:9;
ll tmp = 0;
for(reg int i = 0; i <= end; i ++)
tmp += DFS(k-1, flag&&i==end, sum_1+i, (sum_m*10 + i)%mod);
if(!flag) dp[k][sum_1][sum_m] = tmp;
return tmp;
}
ll Work(ll x){
Bt.clear();
while(x) Bt.pb(x%10), x /= 10;
ll res = 0;
int size = Bt.size();
for(mod = 1; mod <= 9*size; mod ++){
memset(dp, -1, sizeof dp);
res += DFS(size - 1, 1, 0, 0);
}
return res;
}
int main(){
ll A, B;
scanf("%lld%lld", &A, &B);
printf("%lld", Work(B) - Work(A-1));
return 0;
}