牛客练习赛13 幸运数字Ⅳ 发表于 2018-03-18 | 分类于 ACM | 浏览 次 思路这种题目需要仔细观察,来判断出真正的数据范围,$n$个数排列的情况数,也就是$n!$,随$n$增大是非常快的。因为$15!>1e9$,所以当长度大于15时,只要计算最后15个数的第$k$小排列就可以了。 代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107#include "stdio.h"#include "cstring"#include "stdlib.h"#include "map"#include "string"#include "iostream"#include "set"#include "queue"#include "vector"#define FOP freopen("input.txt","r",stdin)#define Met(x,y) memset(x,y,sizeof x)#define L index*2#define R index*2+1using namespace std;typedef long long ll;const ll MAXN=5e5+100;const ll MOD=1e9+7;ll fra[20];void init(){ fra[0]=1; for(int i=1;i<20;++i) fra[i]=fra[i-1]*i; // cout<<fra[15]<<endl;}ll calu(ll lim){ bool ret=0; ll res=0; for(int i=1;i<=12 && !ret;++i) for(int j=0;j<(1<<i) && !ret;++j) { ll digit=1; ll tem=j; ll cs=0; for(int k=0;k<i;++k) { if(tem%2) cs+=digit*7; else cs+=digit*4; tem/=2; digit*=10; } if(cs<=lim) res++; if(cs>=lim) ret=0; } return res;}ll permute[20];bool judge(ll num){ while (num) { if(num%10!=4 && num%10!=7) return 0; num/=10; } return 1;}int main(int argc, char const *argv[]) { // FOP; init(); ll n,kth; cin>>n>>kth; ll ans=calu(n- 15); // cout<<ans<<endl; ll digit=min(15LL,n); bool used[20]; Met(used,0); kth--; for(int i=0;i<digit;++i) { ll tem=kth/fra[digit-i-1]; // printf("%lld %lld\n", kth,fra[digit-i-1]); kth%=fra[digit-i-1]; // printf("%lld %lld\n", kth,fra[digit-i-1]); if(tem>=digit-i) { puts("-1"); return 0; } for(int j=0;j<20;++j) { if(used[j]) continue; if(!tem) { permute[i]=j; used[j]=1; break; } tem--; } // for(int j=0;j<20;++j) // printf("%d ",used[j]); // puts(""); // printf("%lld\n",permute[i]+1); } ll cnt=0; for(int i=max(1LL,n-14),cnt=0;i<=n;++i,cnt++) { // cout<<max(1LL,n-14)+permute[i-max(1LL,n-14)]<<endl; // cout<<i<<endl; ans+=judge(max(1LL,n-14)+permute[i-max(1LL,n-14)])&judge(i); } cout<<ans<<endl; return 0;}