[lnsyoj2228]密码游戏
题意
给定序列 ,要求构造出序列 ,使得对于第 次操作,,每次操作后,将 循环移位一次,若 变为原序列,则将 循环移位一次
赛时 0PTS
DFS 写挂了 awa
sol
对于 和 ,可列出
我们取任意一对 ,得
由于 是 的排列,因此可得
移项,得
这是 的形式,因此我们使用加权并查集维护。(下以 称呼)
可以将 和 使用并查集连接起来,使 成为 的祖宗节点。为了确保最终的根为 ,从而使得 ( 为节点 在并查集中的权值),我们需要使更小的节点成为另一个节点的祖宗,因此,如果 ,需要在等式两边同时 。
在连接时,我们可将 和 的祖宗节点连接,此时,需使 到 的权值和为 ,因此,这条连接的边,权值应为 ,即权值和减去从 到 祖宗节点的权值和。
在枚举时,可以使用一个 vector,将 值相同的 值及其下标记录在一起。在枚举时,只需枚举同一 vector 中相邻的两元素(想一想,为什么?),并进行连边即可
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 100005, M = 30;
int n, m;
int x[N], y[N];
int f[M], d[M];
int a[N], b[N];
vector<PII> g[M];
int find(int x){
if (x == f[x]) return x;
int fa = find(f[x]);
d[x] = ((d[x] + d[f[x]]) % m + m) % m;
return f[x] = fa;
}
int main(){
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i ++ ) f[i] = i;
for (int i = 0; i < n; i ++ ) scanf("%d", &x[i]);
for (int i = 0; i < n; i ++ ) scanf("%d", &y[i]), g[y[i]].push_back({x[i], i});
for (int i = 0; i < m; i ++ )
for (int j = 1; j < g[i].size(); j ++ ){
int u = (g[i][j - 1].x + g[i][j - 1].y) % m, v = (g[i][j].x + g[i][j].y) % m, val = g[i][j].y / m - g[i][j - 1].y / m;
if (u < v) swap(u, v), val *= -1;
int fu = find(u), fv = find(v);
if (fu == fv) continue;
f[fu] = v;
d[fu] = ((val - d[u]) % m + m) % m;
}
for (int i = 0; i < m; i ++ ) find(i), a[i] = d[i];
for (int i = 0; i < n; i ++ ) b[(a[(x[i] + i % m) % m] + i / m) % m] = y[i];
for (int i = 0; i < m; i ++ ) printf("%d ", a[i]);
puts("");
for (int i = 0; i < m; i ++ ) printf("%d ", b[i]);
puts("");
}
分类:
题解 / 2024赛时
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现