Codeforces Beta Round #8 E. Beads

【题意】将所有二进制(允许前导0)中,同时满足字典序不小于其逆序串,取反串和逆序取反串的串提出来,按字典序排序,求第m个。 n <= 50, k <= 10^16.

【解题方法】

来自论文 Codeforences 泛做
算 法 讨 论
首先显然满足题意的二进制串的首位必须是0.
考虑一位一位地确定答案串。假设已经确定了答案串的前k位,我们假设第k + 1位是0,
则要设法统计出满足条件的串的个数s。
那么如果s < m,则答案串第k + 1位为1,同时m = m − s;否则答案串第k + 1位为0.
于是问题转化为,统计所有长度为n的,前缀为prefix的二进制串中,满足题目要求的串
的个数。
这是一类与数位有关的统计问题,于是很容易想到数位dp。
状态dp[i][rev][inv]表示,当前已经确定了前i位和末i位, rev表示前i位与末i位的逆序是
否相等,inv表示前i位与末i位的逆序取反后是否相等。
状态转移比较显然,我们枚举第i+1位和第n−i位的取值,如果它满足prefix的限制,且
新的串没有违反题目要求(可以利用rev,inv和取值判断), 那么更新rev和inv的状态,并累
加到对应的新状态上。
时间复杂度O(16 ∗ N 2 )
特 别 注 意
注意如果n为奇数,那么dp到正中间一位的时候,这一位会同时作为前i位和末i位的组成部
分,需要特判。

我用dp[l][r][rev][inv]来表示上面的状态,做法上面已经说得很清楚了,上代码吧。

【AC代码】
//
//Created by just_sort 2016/12/12
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace __gnu_pbds;
typedef long long LL;
typedef pair<int, LL> pp;
#define MP(x,y) make_pair(x,y)
const int maxn = 1020;
const int maxm = 1<<12;
const int inf = 0x3f3f3f3f;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>order_set;
//head
int n, a[52];
LL k;
bool vis[55][55][2][2];
LL dp[55][55][2][2];
LL dfs(int l, int r, int rev, int inv)
{
    if(l > r) return 1;
    if(vis[l][r][rev][inv]) return dp[l][r][rev][inv];
    vis[l][r][rev][inv] = 1;
    LL &ans = dp[l][r][rev][inv];
    ans = 0;
    for(int i = 0; i < 2; i++){
        if(a[l] == -1 || a[l] == i){
            for(int j = 0; j < 2; j++){
                if(a[r] == -1 || a[r] == j){
                    if(l < r || i == j){ //特判n为奇数的时候,走到最中间的一位
                        if(rev || i <= j){
                            if(inv || i <= 1 - j){
                                ans = ans + dfs(l + 1, r - 1, rev || i < j , inv || i < 1 - j);
                            }
                        }
                    }
                }
            }
        }
    }
    return ans;
}

int main()
{
    memset(a, -1, sizeof(a));
    cin>>n>>k;
    k++;
    a[0] = 0;
    if(dfs(0, n - 1, 0, 0) < k){
        printf("-1\n");
        return 0;
    }
    for(int i = 1; i < n; i++){
        a[i] = 0;
        memset(vis, 0, sizeof(vis));
        LL cur = dfs(0, n - 1, 0, 0);
        if(cur < k){
            k -= cur;
            a[i] = 1;
        }
    }
    for(int i = 0; i < n; i++) cout<<a[i];
}


基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip 个人大四的毕业设计、课程设计、作业、经导师指导并认可通过的高分设计项目,评审平均分达96.5分。主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 [资源说明] 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设或者课设、作业,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96.5分,放心下载使用! 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),供学习参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值