[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;
}
给时光以生命,而不是给生命以时光。

浙公网安备 33010602011771号