const int N=15;
class Solution {
public:
int dp(int cnt[],int num,int len,int offset,int status){
if(len==0) return 1;
int ans=0;
int f=(num/offset)%10;
for(int cur=0;cur<f;cur++){
if((status&(1<<cur))==0) ans+=cnt[len-1];
}
if((status&(1<<f))==0) ans+=dp(cnt,num,len-1,offset/10,status|(1<<f));
return ans;
}
int countSpecialNumbers(int n) {
int len=1;
int offset=1;
int tmp=n/10;
while(tmp){
len++;
offset*=10;
tmp/=10;
}
int cnt[N];
cnt[0]=1;
for(int i=1,k=10-len+1;i<len;i++,k++){
cnt[i]=cnt[i-1]*k;
}
int ans=0;
if(len>=2){
ans=9;
for(int i=2,a=9,b=9;i<len;i++,b--){
a*=b;
ans+=a;
}
}
int f=n/offset;
ans+=(f-1)*cnt[len-1];
ans+=dp(cnt,n,len-1,offset/10,1<<f);
return ans;
}
int numDupDigitsAtMostN(int n) {
return n-countSpecialNumbers(n);
}
};