当前位置: 首页 > news >正文

Luogu P10034 「Cfz Round 3」Circle 题解 [ 蓝 ] [ 背包 DP ] [ 质数筛 ] [ 图论 ] [ 构造 ]

Circle:思维难度并没有很大,难点主要还是细节的特判上。

先转化题意:构造一张无自环的有向图,使得每个点的出度、入度均为 \(1\),并且部分点走 \(l\) 步后必须回到自己。

因为每个点的出度、入度均为 \(1\),所以这张图一定由若干个有向环组成

然后发现,在不能走自环的情况下 \(u\)\(l\) 步回到 \(u\) 的条件相当于 \(u\) 所处的环的长度 \(\bm{len}\) 必须是 \(\bm l\) 的一个约数,否则一定无法返回自己。

同时可以发现,如果一个环的长度不是质数,那么这个环一定可以接着拆分。因为拆出来的环长一定都是原环的约数。由此可知选长度为质数的环一定不劣

于是问题被转化为了,能否从 \(l\)质因子中选择若干个数作为环长,使得环长总和大于等于 \(1\) 的个数,且小于等于 \(n\)。我们只需要把全部的 \(1\) 都放入这个环中,把剩下的 \(0\) 随便编一个环即可。

这显然是一个背包问题,因为 \(\bm l\) 的质因子最多只有 \(\bm{\log l}\),所以时间复杂度 \(O(n\log l)\),注意要记录转移的前驱。最后遍历可能的环长总和,进行构造即可。

注意一些边界条件:

  • \(S\) 全部为 \(0\) 时,随便构造一个排列即可。
  • \(l = 0\),随便构造一个排列即可。
  • 环长总和为 \(n - 1\) 的时候,剩下的一个节点因为无法连自环,所以不是个合法的方案。
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 500005;
ll n, m, a[N], dp[N], pre[N], c[N], ans[N];
bitset<N> vis;
int prm[N], cnt, b[N], bcnt, ccnt;
void init()
{vis[1] = vis[0] = 1;for(int i = 2; i < N; i++){if(vis[i] == 0)prm[++cnt] = i;for(int j = 1; j <= cnt && i * prm[j] < N; j++){vis[i * prm[j]] = 1;if(i % prm[j] == 0) break;}}
}
void solve()
{cin >> n >> m;int num1 = 0;bcnt = 0;for(int i = 1; i <= n && i <= m; i++)if(vis[i] == 0 && m % i == 0)b[++bcnt] = i;for(int i = 1; i <= n; i++){char c;cin >> c;a[i] = c - '0';num1 += a[i];}if(num1 == 0 || m == 0){for(int i = 1; i < n; i++) cout << i + 1 << " ";cout << 1 << "\n";return;}memset(dp, 0, sizeof(dp));dp[0] = 1;for(int i = 0; i <= n; i++){if(dp[i] == 0) continue;for(int j = 1; j <= bcnt; j++){int v = i + b[j];if(v > n) continue;if(dp[v] == 0){dp[v] = 1;pre[v] = b[j];}}}vector<int> res;for(int i = num1; i <= n; i++){if(i == n - 1) continue;if(dp[i]){int now = i;while(now){res.push_back(pre[now]);now -= pre[now];}break;}}if(res.size() == 0){cout << "-1\n";return;}ccnt = 0;for(int i = 1; i <= n; i++)if(a[i] == 1)c[++ccnt] = i;for(int i = 1; i <= n; i++)if(a[i] == 0)c[++ccnt] = i;int cur = 0;for(auto itm : res){for(int i = 1; i < itm; i++){++cur;ans[c[cur]] = c[cur + 1];}++cur;ans[c[cur]] = c[cur - itm + 1];}if(cur != n){for(int i = cur + 1; i < n; i++)ans[c[i]] = c[i + 1];ans[c[n]] = c[cur + 1];}for(int i = 1; i <= n; i++) cout << ans[i] << " ";cout << "\n";
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);init();int t;cin >> t;while(t--) solve();return 0;
}
http://www.hskmm.com/?act=detail&tid=35299

相关文章:

  • 2025.10.20模拟赛
  • SQLite简单使用
  • 新学期每日总结(第12天)
  • 2025.10.20总结 - A
  • CF2107E Ain and Apple Tree
  • 傻瓜式处理kauditd0病毒程序记录
  • win10 升级 win11 后时间更新失败
  • 2025,为什么公众号编辑器排版决定阅读完成率?——一次从流程到结果的深评
  • 软件工程学习日志2025.10.20
  • P14254 分割(树上计数问题) 题解
  • P14262 [ROI 2015 Day1] 自动好友
  • 软件工程第二次团队作业
  • 超越技术范畴:低代码如何重塑企业数字文化
  • 歌手与模特儿
  • 20251019
  • 十六天
  • 计算机毕业设计 基于EChants的海洋气象数据可视化平台设计与建立 Python 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试】
  • https://www.luogu.com.cn/problem/CF1635E
  • ZR 2025 NOIP 二十连测 Day 5
  • SpringBoot整合Redis教程
  • [VIM] reverse multiple lines in VIM
  • Vue 项目 AI 文档增量更新工具操作手册
  • 4060显卡也能玩转AI改图!Flux.1 Kontext Dev GGUF版本超详细入门教程 - 实践
  • 记账:流水报表
  • 2025年法兰保护罩厂家推荐排行榜,阀门保温罩,法兰罩,法兰防溅罩,法兰保护套,专业防护与定制服务优质供应商
  • 英伟达微型AI工作站的架构解析与性能突破
  • 题解 QOJ 7766 [集训队互测 2023] 栞
  • 遥感的基本概念
  • d435i 标定 imu和相机 用来复现vins_fusion - 教程
  • 20232418 2025-2026-1 《网络与系统攻防技术》实验二实验报告