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

8.9 CW 模拟赛 T2. 喝醉的兔子

pVBsaZR.png

思路

首先简单分析一下问题
首先我们要为每只兔子选择一个 \(st_i \in [bas_i + L, bas_i + R]\) 表示其起始位置
然后我们要找到最小的 \(t\), 使得 \(\Big({\times d} + [L, R]\Big)^t\) 之后能到达一个 \(\bmod \, n = 0\) 的数

首先 \(R - L + 1 \leq n - 1\) 且初始区间不满足要求, 否则直接输出 \(0\)
这个时候我们不难发现 \([bas_i + L, bas_i + R]\)\(\bmod \, n\) 意义下是一个区间
因此判断答案是否为 \(0\) 之后, 我们只需要处理一个区间中的最小答案即可

\(ans_x\) 表示 \(x\) 通过多少次 \(\Big({\times d} + [L, R]\Big)\) 之后能到达一个 \(\bmod \, n = 0\) 的数
每次就是对 \(ans\) 的一个 \(\text{RMQ}\) 问题

下面都在 \(\bmod \, n\) 意义下讨论
简单的情况下, 我们可以直接连边 \(\Big({x \times d} + [L, R]\Big) \to x\), 对于 \(x \bmod n = 0\), \(dis_x = 0\), 然后跑一个最短路即可

但是这个时候我们发现, 我们的边数是 \(O(n^2)\) 的, 会 TLE
因此我们需要优化一下边数

不难发现每次连边可以表示为向至多两个区间连边, 因此使用线段树优化建图即可
综合复杂度 \(\mathcal{O} \bigg\{T \Big(n \log n + q\Big) \bigg\}\)

代码

#include <bits/stdc++.h>
#define int long long
// const int MAXN = 2e6 + 50000;
const int MAXN = 300;
const int INF = 1e18;class SOLVER {
private:int n, d, LC, RC, q;struct EDGE { int to, w, nxt; } edge[MAXN << 2];int head[MAXN], ecnt = -1;void addedge(int u, int v, int w) { edge[++ecnt] = {v, w, head[u]}, head[u] = ecnt; }int ans[MAXN];int ST[MAXN << 2][22];bool check(int x) { return ((x + LC) % n == 0 || (x + LC) % n > (x + RC) % n); }int ncnt;int lc[MAXN << 2], rc[MAXN << 2];void build(int &o, int l, int r) {if (l == r) { o = l; return; }o = ++ncnt;int mid = (l + r) >> 1;build(lc[o], l, mid);build(rc[o], mid + 1, r);addedge(lc[o], o, 0); addedge(rc[o], o, 0);}void connect(int o, int l, int r, int L, int R, int from) {if (l >= L && r <= R) { addedge(o, from, 1); return; }int mid = (l + r) >> 1;if (L <= mid) connect(lc[o], l, mid, L, R, from);if (R > mid) connect(rc[o], mid + 1, r, L, R, from);}int vis[MAXN << 2];public:void solve() {ecnt = -1;memset(lc, 0, sizeof lc), memset(rc, 0, sizeof rc);memset(head, -1, sizeof head); memset(vis, false, sizeof vis);scanf("%lld %lld %lld %lld %lld", &n, &d, &LC, &RC, &q); ncnt = n - 1;if (RC - LC + 1 >= n) {for (int i = 1; i <= q; i++) printf("0\n");return;}/*处理建图*/int root; build(root, 0, n - 1);for (int i = 0; i < n; i++) {/*处理 [id + L % n, id + R % n]*/int id = (i * d) % n;// printf("%lld %lld %lld\n", (id + LC) % n, (id + RC) % n, i);if ((id + LC) % n <= (id + RC) % n) {int l = (id + LC) % n, r = (id + RC) % n;connect(root, 0, n - 1, l, r, i);} else {int l1 = (id + LC) % n, r1 = n - 1;int l2 = 0, r2 = (id + RC) % n;connect(root, 0, n - 1, l1, r1, i);connect(root, 0, n - 1, l2, r2, i);}}// printf("----------------------------------------------------------------------");// for (int u = 0; u <= ncnt; u++) {//     for (int e = head[u]; ~e; e = edge[e].nxt) {//         int v = edge[e].to, w = edge[e].w;//         printf("%lld %lld %lld\n", u, v, w);//     }// }/*从 0 开始跑最短路*/std::deque<int> dq;dq.push_back(0);for (int i = 0; i <= ncnt; i++) ans[i] = INF;ans[0] = 0;while (!dq.empty()) {int u = dq.front(); dq.pop_front();if (vis[u]) continue;vis[u] = true;for (int e = head[u]; ~e; e = edge[e].nxt) {int v = edge[e].to, w = edge[e].w;if (ans[v] > ans[u] + w) {ans[v] = ans[u] + w;if (w == 0) dq.push_front(v);else dq.push_back(v);}}}/*建立 ST 表*/for (int i = 0; i < n; i++) ST[i][0] = ans[i];for (int j = 1; j <= 20; j++) {for (int i = 0; i + (1 << j) - 1 < n; i++) ST[i][j] = std::min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);}for (int i = 1, bas; i <= q; i++) {scanf("%lld", &bas);bas %= n;if (check(bas)) { printf("0\n"); continue; }/*求 [bas + LC, bas + RC] 中的最小答案*/int l = (bas + LC) % n, r = (bas + RC) % n;int res = INF;if (l <= r) {int k = std::log2(r - l + 1);res = std::min(res, std::min(ST[l][k], ST[r - (1 << k) + 1][k]));} else {/*先处理 l, n - 1*/int k = std::log2(n - l);res = std::min(res, std::min(ST[l][k], ST[n - (1 << k) + 1][k]));/*再处理 0, r*/k = std::log2(r + 1);res = std::min(res, std::min(ST[0][k], ST[r - (1 << k) + 1][k]));}if (res == INF) printf("-1\n");else printf("%lld\n", res);}}
} MAIN;signed main() {// freopen("ex_calculator2.in", "r", stdin);// freopen("ex_calculator2.out", "w", stdout);int _; scanf("%lld", &_);while (_--) MAIN.solve();return 0;
}

总结

非常简单的一种优化建图方式

我草我草

http://www.sczhlp.com/news/21061/

相关文章:

  • 2025年《财富》中国40位40岁以下的商界精英
  • 洛谷题单指南-状态压缩动态规划-P4045 [JSOI2009] 密码
  • 回顾一下WPF原生实现命令
  • 外贸网站源代码亚马逊关键词快速优化
  • 企业信息怎么查询微信搜索seo优化
  • 如何判断一个网站是php还是asp商品关键词举例
  • 做网站刷东西windows优化大师功能
  • 网站建设情况简介如何在百度发布广告
  • 做网站需要字体切换求几个微信推广平台
  • 广州网站改版 网站建设全国最新疫情实时状况地图
  • 怎样做收费网站互联网推广怎么找渠道
  • MySQL EXPLAIN 结果表详解
  • linux常用命令
  • python的音频处理
  • webrtc-streamer如何在centos7上进行开机自启动配置(教程)
  • 日本做a的动画视频在线观看网站站长之家
  • 重庆宣传网站怎么做我要软文网
  • 建设类网站有哪些免费com域名注册网站
  • 门户网站怎么建设需要多长时间公司网站如何制作
  • ai本地部署有什么用?盘点一款用途齐全工具给你
  • 使用Buildroot编译AMD/Xilinx Zynq ZC702 单板 Linux (内核和文件系统)
  • ​​在线客服聊天前端组件:从一段客服插件代码说起​
  • Keyboard Maestro Tokens 使用方法
  • 网站制作帐户设置网络推广引流
  • 网站开发过时了淘宝关键词排名优化技巧
  • php html5企业网站源码互联网平台推广怎么做
  • 温州网站搭建seo点击软件
  • 网站的运作流程本周时事新闻概要10条
  • 苹果做安卓游戏下载网站好企业营销平台
  • iis如何做网站管理器武汉seo网络优化公司