[Test 2016-5-19]
数字
【问题描述】
我们定义一个正整数的位积等于各个位数字的乘积,例如2612的位积是2×6×1×2=24。
定义一个数的自积该数本身与该数位积的乘积。例如,2612的自积等于2612×24=62688
给你两个正整数A和B,计算有多少个数的自积在A到B之间。
【输入格式】
第一行包含两个整数A和B(1<=A<=B<10^18)。
【输出格式】
输出有多少个数的自积在A到B之间。
【样例输入1】20 30
【样例输出1】2
【样例输入2】145 192
【样例输出2】4
【样例输入3】2224222 2224222
【样例输出3】1
【样例说明】样例2中19、24、32和41的自积分别为171、192、192和164。
【数据范围】25%的数据,A,B<=10^8 40%的数据,A,B<=10^12
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; typedef long long ll; ll A, B, Nw, ret, fac[20]; int num[20], lim[20], w[20]; int cnt; void FJ(ll x){ cnt = 0; while(x){ lim[++ cnt] = x % 10; x /= 10; } } ll check(ll x){ ll ret = 0, n = Nw / x; int len = 0; if(n == 0)return 0; for(int i = 1; i < 10; i ++)len += num[i]; for(int i = 1; i < 10; i ++)w[i] = num[i]; if(len == 0)return 0; FJ(n); if(cnt < len)return 0; if(len < cnt){ ret = fac[len]; for(int i = 1; i < 10; i ++) ret /= fac[num[i]]; return ret; } for(int i = len; i > 0; i --){ for(int j = 1; j < lim[i]; j ++){ if(w[j]){ w[j] --; ll c = fac[i - 1]; for(int k = 1; k <= 9; k ++) c /= fac[w[k]]; w[j] ++; ret += c; } } if(!w[lim[i]])return ret; -- w[lim[i]]; } return ret + 1; } void dfs(int dep, ll SUM, ll MUL){ if((double)MUL * SUM > Nw)return; if(dep == 10){ret += check(MUL); return;} for(int i = 0; (double)SUM * MUL <= Nw; i ++){ num[dep] = i; dfs(dep + 1, SUM, MUL); SUM = SUM * 10 + dep; MUL = MUL * dep; } num[dep] = 0; } ll solve(ll x){ Nw = x; ret = 0; dfs(1, 0, 1); return ret; } int main(){ freopen("num.in", "r", stdin); freopen("num.out", "w", stdout); fac[0] = 1; for(int i = 1; i < 20; i ++)fac[i] = fac[i-1] * i; cin >> A >> B; cout << solve(B) - solve(A - 1) << endl; return 0; }
给时光以生命,而不是给生命以时光。