传送门
我这个人一向不喜欢在洛谷里写题解 但是刚才
80
80
80分看了半个点题解没找到任何有用的信息 发现题解写的都奇奇怪怪的 真的误导我这种不知道错哪里的 所以我决定自己写一个
首先第一眼看到这个题以为是暴力题
(
(
(我看这个题是在一个大一新手同学那里看的 我以为是简单题
结果数据是
1
e
9
1e9
1e9 给我吓一跳
冥思苦想后发现
k
k
k也是
1
e
9
1e9
1e9的 考虑到
13
!
=
6227020800
13!=6227020800
13!=6227020800 那就意味着当
n
n
n很大时 最多也只有后面
13
13
13位会参与全排列 前面的根本不会动
所以这个题就很简单了
当
n
>
13
n>13
n>13时,就将后
13
13
13个数进行全排列
对于前面的数 因为数根本没有动 因此幸运数本身的位置也是幸运数 输出幸运数的个数即可
对于后面的数 直接一个一个判断就完事了
当
n
≤
13
n\le13
n≤13时 直接进行全排列 一个一个判断
对于求全排列的方法 这里应用到逆康托展开 这点其他题解里都说的挺明白的 就不细说了
不会康托展开的仔细想想也能想出来 就是个找规律问题
我为什么错呢 因为当
n
≤
13
n\le13
n≤13时 我没判断当
4
4
4在
7
7
7的位置和
7
7
7在
4
4
4的位置
为什么说题解写的不好呢 因为大多数题解在计数
n
>
13
n>13
n>13时 前面没动的幸运数应用到了数位
d
p
dp
dp
但其实对于
i
i
i位数的幸运数只有
2
i
2^i
2i个 一共也只有
1022
1022
1022个幸运数 直接暴力枚举幸运数即可 完全没必要用数位
d
p
dp
dp 只会疑惑看代码的人 不知道为什么题解除了第一个清一色数位
d
p
dp
dp
第一个题解为什么我也觉得不好呢 因为他在查前面没动的幸运数非常麻烦 我真的不知道为什么 那哥们自己都说了幸运数最多也不超过
2
9
2^9
29个 直接查就完事了呗 为啥还要分那么多情况
上代码↓
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll fac[20];
void set_fac(){
fac[0]=1LL;
for(int i=1;i<=13;i++)fac[i]=fac[i-1]*i;
}
int seq[20];
void decontor(int n, int p){
p-=1;
vector<int> res,ans;
for(int i=1;i<=n;i++)res.push_back(i);
for(int i=n;i;i--){
int now=p/fac[i-1];p%=fac[i-1];
ans.push_back(res[now]);
res.erase(res.begin()+now);
}
for(int i=1;i<=n;i++)seq[i]=ans[i-1];
}
int lnum[5000],pow2[20],num=2;
void set_lnum(){
pow2[0]=1;
for(int i=1;i<=9;i++)pow2[i]=pow2[i-1]<<1;
pow2[0]=0;lnum[1]=4,lnum[2]=7;
for(int i=1;i<=8;i++){
int fst=num-pow2[i]+1,lst=num;
for(int j=fst;j<=lst;j++)
lnum[++num]=lnum[j]*10+4,lnum[++num]=lnum[j]*10+7;
}
lnum[num+1]=int(1e9)+1;
}
bool check(int x){
while(x){
if(x%10!=4&&x%10!=7)return false;
x/=10;
}
return true;
}
int n,k,ans;
int main(){
cin>>n>>k;
set_lnum();set_fac();
if(n<13&&k>fac[n]){puts("-1");return 0;}
decontor(min(n,13),k);
if(n<=13){
if(seq[4]==4)ans++;
if(seq[7]==7)ans++;
if(seq[4]==7)ans++;
if(seq[7]==4)ans++;
}
else{
for(int i=1;lnum[i]<=n-13;i++)ans++;
for(int i=n-12;i<=n;i++){
if(check(i)&&check(seq[i-n+13]+n-13))ans++;
}
}
cout<<ans<<endl;
}