首页 > 其他 > 详细

太鼓达人

时间:2019-10-28 16:16:10      阅读:80      评论:0      收藏:0      [点我收藏+]

https://loj.ac/problem/10110

题目描述

??有一个0、1环,有M个节点,并且满足从一个点出发顺时针K个节点所连接成的0、1串(共M个)都不相同,给出K,求最大的M和字典序最小的方案。

思路

??我们考虑已知\(K\),那么二进制的排列总共有\(2K\)种,因此我们可以先证明,必定存在一种方案,使得\(M\)的排列满足这一条件。我们将\(K-1\)位的二进制看做点,把\(K\)位的二进制看做边,那么\(a->b\)的边即为在\(a\)后面加一个数字(\(0\)\(1\)),这个二进制的后\(K\)位为\(b\),那么这样每个点必定有两条出边和两条入边,因此必定存在欧拉回路。由此归纳,对于任意\(K\),最大的\(M\)均为\(2K\)

??接下啦考虑如何求字典序最小的方案。显然对于欧拉回路,从路径上的任意一点出发都可以,所以前\(K-1\)位必定是\(0\),接下来进行\(dfs\),我们假设访问到当前节点为\(x\),那么记\(x1\)为在\(x\)后加一位\(0\)\(x2\)为在\(x\)后加一位\(1\)\(x1\)\(x2\)实际就是边的编号,每次\(x\)的后\(K-1\)位就是节点编号,所以我们可以直接\(dfs\)字典序小的边进行访问。注意要倒序输出,因为正序访问,答案是倒着存的。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1<<13;
int ans[N],cnt,k,maxx;
bool vis[N];
void dfs(int x)
{
    int x1=(x<<1)&maxx,x2=x1+1;
    if(!vis[x1])
    {
        vis[x1]=1;
        dfs(x1);
        ans[++cnt]=0;
    }
    if(!vis[x2])
    {
        vis[x2]=1;
        dfs(x2);
        ans[++cnt]=1;
    }
}
int main() 
{
    int m;
    scanf("%d",&k);
    m=(1<<k);maxx=m-1;
    dfs(0);
    printf("%d ",m);
    for(int i=1;i<k;i++)printf("0");
    for(int i=m;i>=k;i--)
        printf("%d",ans[i]);
    return 0;
}

太鼓达人

原文:https://www.cnblogs.com/fangbozhen/p/11752878.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!