P10959 月之谜
P10959 月之谜
前置知识
数位 dp 或者记忆化 dfs(不会的看 oiwiki 链接)。
思路
暴力深搜
考虑记忆化搜索 dfs(int pos,int S,int cnt,bool f)。第一个是位数,第二个是现在搜出来的数字是什么,第三位是数位和,第四位是是否可以任意选择。记忆化数组是 \(vis_{pos,S,cnt}\) 只记录 \(f=1\) 的情况。
正解
发现直接数位 dp 样例都过不去。所以我们可以考虑用取模来剪枝,只是会多跑几十次数位 dp 而已。具体来说就是枚举模数让 S%=mod 只要在递归结束时判断 \(cnt=mod\) 与 \(S=0\) 就可以了。
ACcode
#include <bits/stdc++.h>
using namespace std;
#define freop(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define int long long
#define double long double
#define re register
#define endl '\n'
#define inf 0x7f7f7f7f7f7f7f7f
#define lowbit(x) (x&-x)
#define pii pair<int,int>
#define fir first
#define sec second
#define umap unordered_map
#define uset unordered_set
const int N=20,M=100;
int a,b,tot,vis[N][M][M][M],num[N],mod;
inline int dfs(int pos,int S,int cnt,bool f){
if(!pos) return !(cnt^mod)&&!S;
if(vis[pos][S][cnt][mod]^(-1)&&f) return vis[pos][S][cnt][mod];
int sum=0;
int mx=(f?9:num[pos]);
for(int i = 0;i<=mx;++i) sum+=dfs(pos-1,(S*10+i)%mod,cnt+i,f|(i<num[pos]));
if(f) vis[pos][S][cnt][mod]=sum;
return sum;
}
inline int js(int x){
tot=0;
while(x) num[++tot]=x%10,x/=10;
int sum=0;
for(mod=1;mod<=tot*9;++mod) sum+=dfs(tot,0,0,0);
return sum;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freop();
//↑以上为初始化↑
//------------------------------
memset(vis,-1,sizeof(vis));
while(cin >> a >> b) cout << js(b)-js(a-1) << endl;
return 0;
}

浙公网安备 33010602011771号