• [Codeforces 8E] Beads


    Brief Intro:

    将所有n位二进制串中满足字典序不大于其逆序串,取反串,逆序取反串中按字典序排序的第m个输出

    n<=50

    Algorithm:

    首次接触数位DP的题目

    根据数据范围,我们不能枚举。从而只能一位一位确定

    由于要求字典序第m大的,我们可以通过求出如果当前位为0的个数来确定该位为0还是1

    接下来就是典型的数位DP了

    数位DP其实也就是一个记忆化的过程,同时在状态中用变量对上界加以标识

    此题中即为dp[cur][rev][inv],后两位表示是否达到反串上界和逆串上界

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    
    ll n,k,dp[55][2][2],res[55];
    
    ll solve(ll cur,ll rev,ll inv)
    {
        if(dp[cur][rev][inv]>-1) return dp[cur][rev][inv]; //记忆化
        if(cur*2>=n) return dp[cur][rev][inv]=1;
        
        ll &ret=dp[cur][rev][inv]=0;
        for(int i=0;i<2;i++)
            if(res[cur+1]==i || res[cur+1]==-1)
                for(int j=0;j<2;j++)
                    if(res[n-cur]==j || res[n-cur]==-1)
                        if((i==j || 2*cur+1!=n) && (!rev || i<=j) && (!inv || i<=1-j))
                            ret+=solve(cur+1,rev&(i==j),inv&(i!=j));
        return ret;
    }
    
    int main()
    {
        cin >> n >> k;k++;
        
        memset(dp,-1,sizeof(dp));
        memset(res,-1,sizeof(res));
        
        if(solve(0,1,1)<k)
            return cout << -1,0;
        
        for(int i=1;i<=n;i++)
        {
            memset(dp,-1,sizeof(dp));
            res[i]=0;
            ll t=solve(0,1,1); //判断该位的值
            if(t<k) k-=t,res[i]=1;
            cout << res[i];
        }
        return 0;
    }

    Review:

    1、对于求第k个满足要求的数时

    可以通过  已知前缀枚举满足要求的个数+逐位确定每一位 的方法来取代枚举

    2、数位DP的特殊点仅仅在对上界状态的维护,其余和记忆化搜索相同

  • 相关阅读:
    XML节点处理
    Log4Net使用记录
    WPF选择文件夹及文件操作
    SQL 一些语句记录
    一篇MSSQL事务的测试文章
    游标示例
    WPF实现多线程加载数据
    MS SQL索引学习
    Entity Framework 利用 Database.SqlQuery<T> 执行存储过程,并返回Output参数值
    手持移动端特殊链接:打电话,发短信,发邮件
  • 原文地址:https://www.cnblogs.com/newera/p/9017139.html
Copyright © 2020-2023  润新知