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;
}
posted @ 2026-10-21 21:24  elon_giao  阅读(3)  评论(0)    收藏  举报