解题思路:给定排列第k小序列,求出序列。这是就利用道理逆康托展开X = a[n](n-1)! + a[n-1](n-2)!.....a[1]*0.康托展开自行百度,很好理解的。
题目链接:点击打开链接
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e4 + 10;
const ll VAL = 5e9;
int n,m,a[2] = {4,7},b[20],order[20],num[20];
ll per[20] = {1},luck[mx],top = 0;
void dfs(ll x)
{
for(int i=0;i<2;i++)
{
if(x*10+a[i]>VAL) break;
luck[++top] = x*10 + a[i];
dfs(x*10+a[i]);
}
}
int main()
{
dfs(0),sort(luck+1,luck+top+1);
//cout << luck[top] << endl;
for(int i=1;i<=13;i++) per[i] = i*per[i-1];
scanf("%d%d",&n,&m);
if(n<13&&m>per[n]) return puts("-1");
int k = lower_bound(per+1,per+1+13,m) - per;
int ans = upper_bound(luck+1,luck+1+top,n-k) - luck - 1;
for(int i=1;i<=k;i++) num[i] = n - k + i;
m--;
for(int i=k;i>=1;i--){
int po = m/per[i-1],cnt =0;
for(int j=1;j<=k;j++)
if(!b[j]){
if(cnt==po) { order[k-i+1] = j,b[j] = 1; break; }
cnt++;
}
m = m%per[i-1];
}
for(int i=1;i<=k;i++){
if(luck[lower_bound(luck+1,luck+1+top,num[i])-luck]==num[i])
if(luck[lower_bound(luck+1,luck+1+top,order[i]+n-k)-luck]==order[i]+n-k)
ans++;
}
printf("%d\n",ans);
return 0;
}