Numb 题解

前言

五一网课的例题,但是网上没有题解,所以来写一篇,就当攒 RP 了。题目可以在这里提交。原题是 Baekjoon - 19083,但是交不了?

题目简述

给你一个偶数 \(n\),求一个二进制数 \(x=\overline {a_1 a_2 \dots a_n}\),满足:

  1. \(x \equiv 0 \pmod{n}\)
  2. \(\forall i \in [1, n]\)\(\overline {a_1 a_2 \dots a_i} \bmod n\) 互不相同;
  3. 不含有前导 \(0\)

题目分析

我不说的话,你能想到这是一道欧拉回路的题?

首先看到取模,前缀,很容易想到图论。点权是当前模 \(n\) 意义下的值,出边有两条分别是在当前缀后加上 \(0\) 或者 \(1\)。于是连边:

\(u \rightarrow 2u \bmod n\)

\(u \rightarrow 2u + 1 \bmod n\)

问题转变成了初始从 \(0\) 出发,不重不漏走过所有的点,最后在 \(0\) 处停下。所以这是一个哈密顿回路问题。

进一步分析图的性质,发现 \(u\)\(u + \cfrac{n}{2}\) 连出去的点是一样的,所以看做一个大点,图上有 \(\cfrac{n}{2}\) 个大点,分别是 \(\left (0, \cfrac{n}{2} \right), \left(1, \cfrac{n}{2} + 1 \right), \ldots, \left(\cfrac{n}{2} - 1, n -1 \right)\)。每个大点有两条出边和两条入边。为了不重不漏地访问小点,我们可以不重不漏访问大点之间的边。所以就是一个简单的欧拉回路的问题了。至于不能有前导零,我们固定第一位是 \(1\) 就可以了。

代码

#include <cstdio>
#include <cstring>
#pragma GCC target("avx", "sse2", "sse3", "sse4", "mmx")
typedef unsigned int uint;

uint t, n, m, top;

bool vis[3000001][2];
bool ans[6000001];

inline uint add(uint a, uint b){
	return a + b >= m ? a + b - m : a + b;
}

inline void dfs(uint now){
	if (!vis[now][0]){
		vis[now][0] = true;
		dfs(add(now, now));
		ans[++top] = 0;
	}
	if (!vis[now][1]){
		vis[now][1] = true;
		dfs(add(now, now + 1));
		ans[++top] = 1;
	}
}

inline void solve(){
	scanf("%ud", &n), m = n >> 1, memset(vis, 0, sizeof (bool) * (n)), top = 0, vis[0][1] = 1, dfs(n == 2 ? 0 : 1), ans[++top] = 1;
	for (register int i = top; i; --i) putchar(ans[i] | 48);
	putchar('\n');
}

signed main(){
	for (scanf("%ud", &t); t--; solve());
	return 0;
}

checker.cpp

#include "testlib.h"
#include <vector>

signed main(int argc, char* argv[]) {
	registerTestlibCmd(argc, argv);

	int t = inf.readInt();

	while (t--) {
		int n = inf.readInt();
		std::vector<bool> vis(n, false);
		std::string str = ouf.readLine();
		
		if (int(str.length()) != n) quitf(_wa, "You're too long or too short!");

		for (int i = 1, now = 0; i <= n; ++i) {
			char ch = str[i - 1];
			
			if (ch != '0' && ch != '1') quitf(_wa, "Read '%c' not 0 or 1!", ch);
			
			if (i == 1 && ch == '0') quitf(_wa, "There mustn't be any leading zeros!");
			
			now = (now << 1 | (ch ^ 48)) % n;

			if (vis[now]) quitf(_wa, "Found %d again!", now);
			vis[now] = true;

			if (i == n && now != 0) quitf(_wa, "The number is not divisible by n!");
		}
	}

	ouf.readEof();

	quitf(_ok, "I love yzh!");

	return 0;
}
posted @ 2024-04-23 09:52  XuYueming  阅读(24)  评论(0)    收藏  举报