beautiful number
问题描述
令 A = sum_{i=1}^{n}a_i * {10}^{n-i}(1leq a_i leq 9)A=∑i=1nai∗10n−i(1≤ai≤9)(nn为AA的位数)。若AA为“漂亮的数”当且仅当对于任意1 leq i < n1≤i<n满足a[i] geq a[i+1]a[i]≥a[i+1]且对于任意1 leq i leq n,i < j leq n1≤i≤n,i<j≤n,满足a[i]a[i] mod a[j]=0a[j]=0(例如931是一个“漂亮的数”而87不是),求在区间[L,R][L,R](包含L和R)里“漂亮的数”的个数。
输入描述
第一行包含一个正整数TT(大约100),表示数据的组数。
接下来TT行,每行两个数$L,R(1 leq L leq R leq {10}^{9})$。
输出描述
对于每组数据输出一个正整数表示“漂亮的数”的个数。
输入样例
2 1 11 999999993 999999999
输出样例
10 2由于题目要求各数位从高到低值递减而且还要满足后面必为前面约数的条件,所以从1到1e9里面的数不会很多,可以直接打表过,打表代码太长就不贴了
还是使用数位dp解这道题较好,使用pre代表第len位的前一位数值,经过思考可以知道如果从高到低逐位实现前者为后者的约数,那么就能够满足任意后一位为前者的约数。还有高位可以不断取0,多开一个参数处理就好
#include <iostream> #include <cstring> #include <cstdio> using namespace std; int dp[111][10]; int a[111]; int dfs(int len,int pre,int flag,int d) { if(len==-1) return 1; if(!flag&&dp[len][pre]!=-1) return dp[len][pre]; int end=flag?a[len]:9; int ans=0; for(int i=0;i<=end;i++) { if(d==0||(i<=pre&&i!=0&&pre%i==0)) ans+=dfs(len-1,i,flag&&i==end,d||i); } if(!flag) dp[len][pre]=ans; return ans; } int cacu(int x) { int top=0; while(x) { a[top++]=x%10; x/=10; } return dfs(top-1,0,1,0); } int main() { memset(dp,-1,sizeof(dp)); int T; for(scanf("%d",&T);T;T--) { int l,r; scanf("%d%d",&l,&r); printf("%d ",cacu(r)-cacu(l-1)); } return 0; }