zoukankan      html  css  js  c++  java
  • 牛客练习赛13 D幸运数字Ⅳ . 康托逆展开

    传送门

    题意:中文题面。。

    题解:13的阶乘大于1e9,也就是说如果n大于13,那么只有后半部分大于13 的会进行重排,所以可以把一个数列分为两段,第一段是1到n-12,第二段是n-12到n。我们需要先dfs出幸运数字的所有情况,sort一下,枚举过去如果n-12大于幸运数字则ans++(因为前一段未发生变化,所以在1到n-12里面的幸运数字的下标和其本身是相同的),接下来就只要要求后半段的序列的第k个序列这就用到了康托逆展开(以前学长教过,没想到居然真用上了。。但是敲不仔细,WA了一片)。康托展开是求一个序列他是第几个全排列,逆展开就是求第几个去全排列是谁。具体的去看百度百科吧。。

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <map>
    #include <queue>
    #include <vector>
    #include <cstring>
    #include <iomanip>
    #include <set>
    #define se second
    #define fi first
    #define ll long long
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define Pii pair<int,int>
    #define ull unsigned long long
    #define pb push_back
    #define fio ios::sync_with_stdio(false);cin.tie(0)
    const double Pi=3.14159265;
    const double e=2.71828182;
    const int N=1e5+5;
    const ull base=163;
    using namespace std;
    int str[N];
    ll a[N];
    int tot=0;
    map<ll,int>mp;
    map<ll,int>Bo;
    ll c[1500];
    void dfs(ll x){
        if(x>=1000000000)return ;
        if(x!=0){
            mp[x]=1;
            c[tot++]=x;
        }
        dfs(x*10+4);
        dfs(x*10+7);
    }
    int main(){
        fio;
        int n,k;
        cin>>n>>k;
        ll sum=1;
        dfs(0);
        sort(c,c+tot);
        for(ll i=1;i<=n;i++){
            sum*=i;
            a[i]=sum;
            if(sum>=1000000000)break;
        }
        if(sum<k)return cout<<-1<<endl,0;
        k--;
        int cnt=(n>13?n-12:1);
        ll m=k;
        ll mid=k;
        int ans=0;
        for(int i=0;i<tot;i++){
            if(c[i]>=cnt)break;
            else{
                ans++;
            }
        }
        int num=1;
        for(ll i=(n>13?13:n)-1;i>=1;i--){
            m=mid/a[i];
            mid=mid%a[i];
            int tot=0;
            for(int j=(n>13?cnt:1);j<=n;j++){
                if(!Bo[j])tot++;
                if(tot==m+1){
                    Bo[j]=1,str[num++]=j;
                    break;
                }
            }
        }
        for(int i=(n>13?cnt:1);i<=n;i++)
            if(!Bo[i]){
                str[num]=i;
                break;
            }
        for(int i=1;i<=num;i++){
            if(mp[i+cnt-1]&&mp[str[i]]){
                ans++;
            }
        }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    bzoj3064: Tyvj 1518 CPU监控
    bzoj3272: Zgg吃东西&&3267: KC采花
    bzoj2759: 一个动态树好题
    bzoj4594: [Shoi2015]零件组装机
    bzoj4873: [Shoi2017]寿司餐厅
    bzoj4593: [Shoi2015]聚变反应炉
    codeforces 739E
    bzoj2034: [2009国家集训队]最大收益
    mybatis-generator使用心得
    Linux 各种软件的安装-Jenkins和svn结合
  • 原文地址:https://www.cnblogs.com/Mrleon/p/8594626.html
Copyright © 2011-2022 走看看