比得喜欢幸运数字。这里所说的幸运数字是由4和7组成的正整数。比如,整数47,744,4是幸运数字,而5,17,467就不是。
一天比得梦到由数字1到n组成的第K个字典序排列。要求计算在这个排列中有多少个幸运数所在的位置的编号也是幸运数。
举例如下:
比如排列[1,2,3,4],其中4为幸运数,它所在的位置的下标为4(幸运数),所在此排列中,结果为1.
又如,[1,2,4,3],4所在位置为3。3不是幸运数,所以,结果为0.
样例解释:
排列是由n个元素组成的一个序列,在这个序列中,整数1到n都要有且仅出现一次。
在排列中,第i个元素定义为 ai (1≤i≤n)。
假定有排列a,和排列b。长度均为n。即都是由1到n组成。如果存在i(1≤i≤n)和对于任意j(1≤j<i)使得 ai < bi 且 aj = bj 。我们就说,a的字典序比b的字典序小。
对1到n组成的所有排列进行字典序升序排列。然后取其中的第K个排列,就是第K个字典序排列。
在样例中,最终排列如下:
1 2 3 4 6 7 5
只有第4个位置是幸运数。
Input
单组测试数据 共一行,包含两个整数n和k(1≤n,k≤10^9)表示排列中的元素个数,和第K个字典序排列。
Output
如果k超过出了1到n所有排列数的种数,那么输出“-1”(没有引号)。 否则,输出题目要求结果。
Input示例
7 4
Output示例
1
题解:切成两部分考虑,因为k很小,所以前半部分是连续的1~x直接统计即可,后面直接暴力(只有13个不确定的数)
然后判断即可(有点恶心)
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,m,ans,a[100],f[100],g[100],n1;
long long pd(long long t){
long long n1=0;
while(t){
n1++;
a[n1]=t%10;
t/=10;
if(a[n1]!=4&&a[n1]!=7)return 0;
}
return 1;
}
void dfs(long long x){
if(x>n1)return;
if(x)ans++;
dfs(x*10+4);
dfs(x*10+7);
}
int main(){
long long i,ii,j,t,k,s,la;
scanf("%lld%lld",&n,&m);
t=1;
for(i=2;i<=n;i++){
if(t>m)break;
t*=i;
la=i;
}
if(t<m){
printf("-1");
return 0;
}
ii=la;
k=t;
for(i=1;i<=ii;i++){
g[i]=1;
}
for(i=n-ii+1;i<=n;i++){
k/=(ii-(i-(n-ii+1)));
s=0;
for(j=1;j<=ii;j++)
if(g[j]){
s++;
if(s*k>=m){
m-=(s-1)*k;
g[j]=0;
f[i-(n-ii)]=j+(n-ii);
break;
}
}
}
n1=n-ii;
dfs(0);
for(i=1;i<=ii;i++)
if(pd(f[i])&&pd(n-ii+i))ans++;
printf("%lld\n",ans);
}