Newcoder 70 D.幸運數字Ⅳ(組合數學)
阿新 • • 發佈:2018-12-16
Description
定義一個數字為幸運數字當且僅當它的所有數位都是或者。
比如說,都是幸運數字而都不是。
現在想知道在的第小的排列中,有多少個幸運數字所在的位置的序號也是幸運數字。
Input
第一行兩個整數。
Output
一個數字表示答案。
如果沒有個排列,輸出。
Sample Input
7 4
Sample Output
1
Solution
雖然此處很大,但是由於不大,故字典序第小的排列其前面的大部分數字都不變,最多後面十幾個數字順序改變,用康託展開即可得到後面亂序的十幾個數字,這些數字直接暴力判斷是否對答案有貢獻,前面的~這些數字,就在第個位置上,所以它們對答案的貢獻就是幸運數字的個數,直接列舉九位是還是然後得到一個幸運數字判斷其是否在該區間即可
Code
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<map> #include<set> #include<ctime> using namespace std; typedef long long ll; typedef pair<int,int>P; const int INF=0x3f3f3f3f,maxn=22; int fact[maxn],g[maxn]; bool check(int x) { while(x) { if(x%10!=4&&x%10!=7)return 0; x/=10; } return 1; } int Solve(int n) { g[0]=1; for(int i=1;i<9;i++)g[i]=10*g[i-1]; int ans=0; for(int k=1;k<=9;k++) { int N=1<<k; for(int i=0;i<N;i++) { int temp=0; for(int j=0;j<k;j++) if(i&(1<<j))temp+=4*g[j]; else temp+=7*g[j]; if(temp<=n)ans++; } } return ans; } int main() { fact[0]=1; for(int i=1;i<=12;i++)fact[i]=i*fact[i-1]; int n,k; while(~scanf("%d%d",&n,&k)) { k--; int x=0; for(int i=12;i>=0;i--) if(k>=fact[i]) { x=i+1; break; } if(x>n)printf("-1\n"); else { int mark[maxn],a[maxn]; memset(mark,0,sizeof(mark)); for(int i=x-1;i>=0;i--) { int t=k/fact[i]; k%=fact[i]; for(int j=0;j<x;j++) if(!mark[j]) { t--; if(t<0) { mark[j]=1; a[x-1-i]=j; break; } } } int ans=Solve(n-x); for(int i=0;i<x;i++) if(check(n-x+1+i)&&check(n-x+1+a[i]))ans++; printf("%d\n",ans); } } return 0; }