Codeforces Beta Round #8 E. Beads

来源:互联网 发布:淘宝便宜零食店 编辑:程序博客网 时间:2024/05/17 06:07

【题意】将所有二进制(允许前导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;//headint 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];}


0 0
原创粉丝点击