P1384 幸运数与排列

P1384 幸运数与排列

神奇的(逆)康托展开:求1到n的全排列中字典序第k小的排列

$k<=10^9<13!$,显然$k$最多只会影响后$13$位

前面一大串都是有序从小到大排列的,于是搞个数位dp

后面一小串用逆康托展开求出原串,枚举是否符合条件。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
long long fac[14]={1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800};
int n,k,x,e[12],a[12];
vector <int> p1,p2;
int dfs(int d,int w,int z){//普通的数位dp
    if(!d) return !z;
    if(!w&&!z&&e[d]>-1) return e[d];
    int lim=w?a[d]:9,tot=0;
    for(int i=0;i<=lim;++i)
        if(i==4||i==7||(z&&!i))
            tot+=dfs(d-1,w&&(i==lim),z&&!i);
    if(!w&&!z) e[d]=tot;
    return tot;
}
int solve1(int A){
    int t=0;
    while(A) a[++t]=A%10,A/=10;
    return dfs(t,1,1);
}
bool is(int x){
    for(;x;x/=10) if(x%10!=4&&x%10!=7) return 0;
    return 1;
}
int solve2(){
    --k;
    for(int i=n-x+1;i<=n;++i) p1.push_back(i);
    for(int i=x,v;i>=1;--i){//逆康托展开求原串
        v=k/fac[i-1]; k%=fac[i-1];
        sort(p1.begin(),p1.end());
        p2.push_back(p1[v]);
        p1.erase(p1.begin()+v);
    }int tot=0;
    for(int i=0;i<x;++i)
        if(is(n-x+i+1)&&is(p2[i])) ++tot;
    return tot;
}
int main(){
    scanf("%d%d",&n,&k);
    if(n<13&&k>fac[n]){printf("-1");return 0;}
    while(k>fac[x])++x;
    memset(e,-1,sizeof(e));
    printf("%d",solve1(n-x)+solve2());
    return 0;
}

原文地址:https://www.cnblogs.com/kafuuchino/p/10338589.html

时间: 2024-11-05 22:55:10

P1384 幸运数与排列的相关文章

【蓝桥杯】历届试题 幸运数

  历届试题 幸运数   时间限制:1.0s   内存限制:256.0MB 问题描述 幸运数是波兰数学家乌拉姆命名的.它采用与生成素数类似的“筛法”生成. 首先从1开始写出自然数1,2,3,4,5,6,.... 1 就是第一个幸运数. 我们从2这个数开始.把所有序号能被2整除的项删除,变为: 1 _ 3 _ 5 _ 7 _ 9 .... 把它们缩紧,重新记序,为: 1 3 5 7 9 .... .这时,3为第2个幸运数,然后把所有能被3整除的序号位置的数删去.注意,是序号位置,不是那个数本身能否

蓝桥杯 - 幸运数 (打表)

历届试题 幸运数 时间限制:1.0s   内存限制:256.0MB 问题描述 幸运数是波兰数学家乌拉姆命名的.它采用与生成素数类似的"筛法"生成 . 首先从1开始写出自然数1,2,3,4,5,6,.... 1 就是第一个幸运数. 我们从2这个数开始.把所有序号能被2整除的项删除,变为: 1 _ 3 _ 5 _ 7 _ 9 .... 把它们缩紧,重新记序,为: 1 3 5 7 9 .... .这时,3为第2个幸运数,然后把所有能被3整除的序号位置的数删去.注意,是序号位置,不是那个数本身

51nod 1230:幸运数

51nod 1230:幸运数 题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1230 题目大意:如果一个数各个数位上的数字之和是质数,并且各个数位上的数字的平方和也是质数,则称它为幸运数.例如:120是幸运数,因为120的数字之和为3,平方和为5,均为质数,所以120是一个幸运数字.给定x,y,求x,y之间( 包含x,y,即闭区间[x,y])有多少个幸运数. 数位DP 代码如下: 1 #include <cs

数的排列问题

突然想到一个问题,对于给定的几个数怎样用程序把所有的数的排列全部输出呢 查了一下运用的思想是这样的 其实这个和深度优先搜索很像 把数组分成两个部分下标0~s为排好的,s~e为没有排的 对数的操作从s开始 1 void sort(vector<int> &nums,int s,int e){ 2 for(int i = s ; i<e ;++i){ 3 swap(nums,s,i); 4 sort(nums,s+1,e); } 7 } 对于上图的同一列,先s和s交换(相等,实质没有

幸运数的各位和[Codeforces-109A]

Codeforces Beta Round #84 (Div. 1 Only)  时间限制2000ms,内存限制256MB 问题大意:定义幸运数为十进制表示只包含4.7两个数码的数.例如47.744.4都是幸运数,而5.17.467不是. 已知一个幸运数的各位之和,求满足条件的幸运数的最小值.输入保证$1≤n≤10^6$. 这题用暴力方法就可以做.需要注意题目中的几个信息: 1)输入可能达到$10^6$,因此原数必然超过$10^6÷9>10^5$,因此无论用32位还是64位整数是不可能表示的下的

[51NOD1230]幸运数(数位DP)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1230 dp(l,s,ss)表示长度为l的数各位和为s,各位平方和为ss的幸运数的个数. 1 #include <bits/stdc++.h> 2 #pragma comment(linker, "/STACK:10240000,10240000") 3 using namespace std; 4 5 typedef long long

曦皓的幸运数

[题目描述] 仅包含4或7的数被称为幸运数. 一个序列的子序列被定义为从序列中删去若干个数,剩下的数组成的新序列.两个子序列被定义为不同的当且仅当其中的元素在原始序列中的下标的集合不相等.对于一个长度为N的序列,共有2^N个不同的子序列(包含一个空序列). 一个子序列被称为不幸运的,当且仅当其中不包含两个相同的幸运数. 对于一个给定序列,求其中长度恰好为K的不幸运子序列的个数,答案 mod (10^9+7)输出. [输入描述] 第一行两个正整数N.K,表示原始序列的长度和题目中的K: 接下来一行

有环积分号的单行数式排列规则

使用MathType的用户大部分都知道,有环积分中的积分函数式需要排在两个积分号的居中位置.但是在操作过程中一些用户还不是很了解,本教程将详解有环积分的单行数式排列规则.有环积分样式如下: 在这个数式中,积分函数式“T(m) nk…”.“R(x)+Q(y)”应与“=”对齐,排在两个积分号的居中位置,不能与底线平齐.下面的排法是不正确的: 积分号上下限原则上应该排在它的上面和下面,一般用七号字.如: 在格式上,当上下限在积分号上面和下面时,不能排在上和下的居中位置,而是上限偏右,下限偏左.但如果只

京东笔试之幸运数问题:4,7

题目描述 4和7是两个幸运数字,我们定义,十进制表示中,每一位只有4和7两个数的正整数都是幸运数字. 前几个幸运数字为:4,7,44,47,74,77,444,447... 现在输入一个数字K,输出第K个幸运数. 输入 第一行一个数字T(T<=1000)表示测试数据的组数.对于每组测试数据,输出一个数K 输出 每组数据输出一行,第K个幸运数. 样例输入 351001000000000 样例输出 74744747 77477744774747744747444444447 思路 首先把4和7化为0