你有一组非零数字(不一定唯一),你可以在其中插入任意个0,这样就可以产生无限个数。比如说给定{1,2},那么可以生成数字12,21,102,120,201,210,1002,1020,等等。
现在给定一个数,问在这个数之前有多少个数。(注意这个数不会有前导0).
Solution
可重复康托展开
- 常用数位 dp 套路,枚举哪一位开始比原数小,前方唯一而后方算全排列
- 回避高精度的全排列数计算,考虑到阶乘最多大约算到 50, 开个因子计数桶,然后在桶上操作就可以了
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1005;
char str[N];
int n;
int buc[N];
void push(int x) {
for(int i=2;i<=x;i++) {
while(x%i==0) buc[i]++, x/=i;
}
}
void pop(int x) {
for(int i=2;i<=x;i++) {
while(x%i==0) buc[i]--, x/=i;
}
}
int calc(vector <int> v) {
int sum=0;
for(int i=0;i<10;i++) sum+=v[i];
for(int i=2;i<=sum;i++) push(i);
for(int i=0;i<10;i++) {
for(int j=2;j<=v[i];j++) pop(j);
}
int ans=1;
for(int i=2;i<=50;i++) while(buc[i]) buc[i]--, ans*=i;
return ans;
}
signed main() {
cin>>str+1;
n=strlen(str+1);
vector <int> v;
for(int i=0;i<10;i++) v.push_back(0);
for(int i=1;i<=n;i++) v[str[i]-'0']++;
int ans=0;
for(int i=1;i<=n;i++) {
for(int j=0;j<str[i]-'0';j++) {
if(v[j]==0) continue;
v[j]--;
ans+=calc(v);
v[j]++;
}
v[str[i]-'0']--;
}
cout<<ans<<endl;
}
原文地址:https://www.cnblogs.com/mollnn/p/12317129.html
时间: 2024-11-05 19:31:09