zoukankan      html  css  js  c++  java
  • [康托展开]luogu P1384 幸运数与排列

    题面

    https://www.luogu.com.cn/problem/P1384

    分析

    康托展开,即$k=a_n*(n-1)!+a_{n-1}*(n-2)!+cdot cdot cdot  +a_1*0!$,$a_i$ 表示第i位上的数在尚未出现的元素中的排名

    这题对k做逆康托展开还原序列前13位即可(13!已经大于最大值了,剩余部分不会变)然后统计不变部分的幸运数个数,对于变化的部分单独求在幸运数位置上的幸运数个数。

    由于康托展开是一种类似数位DP的定理,所以也可以归类这题为数位DP

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int N=2e6+10;
    int cnt,ncnt,c;
    ll n,k,fact[21],pow[10],l[N],need[21],num[21],rev[21],ans;
    
    void Get_Lucky(int dep,ll x) {
        if (x+pow[dep]*4<=n) Get_Lucky(dep+1,l[++cnt]=x+pow[dep]*4);
        if (x+pow[dep]*7<=n) Get_Lucky(dep+1,l[++cnt]=x+pow[dep]*7);
    }
    
    bool Lucky(ll x) {for (;x;x/=10) if (x%10!=4&&x%10!=7) return 0;return 1;}
    
    int main() {
        scanf("%lld%lld",&n,&k);k--;
        fact[0]=1;for (int i=1;i<=20;i++) fact[i]=fact[i-1]*i;
        pow[0]=1;for (int i=1;i<10;i++) pow[i]=pow[i-1]*10;
        if (n<=12&&fact[n]<=k) return printf("-1"),0;
        Get_Lucky(0,0);sort(l+1,l+cnt+1);
        if (cnt==0) return printf("0"),0;
        for (c=20;c&&fact[c]>k;c--);
        for (int i=cnt;l[i]>=n-c;i--) need[++ncnt]=l[i];
        for (int i=n-c;i<=n;i++) num[i-n+c+1]=i;
        for (int i=1,j=c;j;j--,i++) {
            rev[i]=num[k/fact[j]+1];
            for (int r=k/fact[j]+1;r<=j;r++) num[r]=num[r+1];
            k%=fact[j];
        }
        rev[c+1]=num[1];
        for (int i=1;i<=ncnt;i++) if (Lucky(rev[need[i]-n+c+1])) ans++;
        printf("%lld",ans+cnt-ncnt);
    }
    View Code
  • 相关阅读:
    Debian / Ubuntu 更新内核并开启 TCP BBR 拥塞控制算法
    axios 常用的几个方法
    doT模板双重循环模板渲染方法
    利用闭包,在不设置全局变量的情况下,完成再次点击退出功能
    技术支持
    隐私政策
    apicloud踩坑集锦
    apicloud运行机制
    apcloud混合式开发app学习笔记
    bootstrap 弹出框 另类运用
  • 原文地址:https://www.cnblogs.com/mastervan/p/13855154.html
Copyright © 2011-2022 走看看