51nod1635 第K个幸运排列

18 篇文章 0 订阅
5 篇文章 0 订阅
题目来源:  CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 80  难度:5级算法题
 收藏
 关注

比得喜欢幸运数字。这里所说的幸运数字是由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); 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值