zoukankan      html  css  js  c++  java
  • AcWing310 启示录(数位dp)

    这道题因为要求的是第k大的魔鬼数

    所以我们可以采用二分的方法,用k-1来二分,这样就可以找到最左边的>=k的,也就是第k大

    之后是数位dp,题目要求的是666,因此我们考虑用两位表示前一位填p1,前前位填p2。剩下的还要保存在这个数之前是否已经存在魔鬼数,这便与边界判断数是否成立,还有一维是老套路,看是否是最大的

    #include<iostream>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long ll;
    vector<int> num;
    int f[20][2][2][2][2];
    int k;
    int dfs(int cur,int p2,int p1,int m,int flag){
        if(cur==(int)num.size())
        return m==1;
        if(f[cur][p2][p1][m][flag]!=-1)
        return f[cur][p2][p1][m][flag];
        int v=9;
        if(flag)
        v=num[cur];
        int i;
        long long ans=0;
        for(i=0;i<=v;i++){
            ans+=dfs(cur+1,p1,i==6,m||(p1&&p2&&(i==6)),flag&&(i==v));
        }
        return f[cur][p2][p1][m][flag]=ans;
    }
    int check(ll n){
        num.clear();
        while(n){
            num.push_back(n%10);
            n/=10;
        }
        reverse(num.begin(),num.end());
        memset(f,-1,sizeof f);
        int ans=dfs(0,0,0,0,1);
        return ans<=k;
    }
    int main(){
        int t;
        cin>>t;
        while(t--){
            cin>>k;
            k--;
            ll l=0,r=1e10;
            while(l<r){
                ll mid=(l+r)>>1;
                if(check(mid))
                l=mid+1;
                else
                r=mid;
            }
            cout<<l<<endl;
        }
    }
    View Code
  • 相关阅读:
    Processing编程【2】
    哈工大锐捷网络处理问题
    processing编程【1】
    verilog入门知识【2】
    数字电路与逻辑设计知识清单【一】
    四位密码锁*电子密码锁的设计
    verilog入门知识【1】
    【Android】入门的一些知识。
    Andriod 入门
    关于Hibernate和Strtus2的xml提示问题
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12697482.html
Copyright © 2011-2022 走看看