1 条题解
-
0
自动搬运
来自洛谷,原作者为

ouuan
如果奇迹有颜色的话,那么其中之一必是橙色的吧。搬运于
2025-08-24 22:05:44,当前版本为作者最后更新于2018-11-03 23:11:24,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
〇、暴力
首先这题有一个比较好想的暴力:对于每对可以传递答案的同学连单向边,然后从每个可以独立作出的同学开始dfs。
这个暴力主要有两个问题:
-
边数太多,最多可以达到 的级别。
-
每次询问都要dfs一次。
下面将分别进行讲解:
一、连边
其实对于每个同学,只需要向左右两边最近的能够接收到的同学各连一条边即可。
不妨令当前同学为第 位同学,他左边最近的能够接收到他的广播的同学为 .
若存在比 更远的一位同学 能够接收到 的广播,那么 一定能够接收到 的广播,而 又能接收到 的广播。
所以, 向左只用连 这条边即可。向右是类似的。一共只要连不到 条边。
说得好,怎么实现呢?用一个栈,从左往右扫一遍,如果栈顶无法接收到当前同学的广播就弹出,若栈非空就向栈顶连边,然后将当前同学入栈。然后再从右往左扫一遍就好了。
二、单次dfs
注:这里的单次dfs不是指只dfs一次,而是指所有的dfs过程总复杂度为
每次询问的时候dfs的起点都是 中最大的一些,所以先对 排序。
然后按顺序依次进行dfs就可以啦!停!怎么dfs?怎么回答询问?
从大到小枚举 ,每次把 的点作为起点dfs,然后记录每个询问 的答案,就可以回答询问啦!
你当这题没有修改吗???事实上,修改造成的影响只有 , 两种,所以分两种情况, 表示 时询问 的答案, 表示 时询问 的答案。计算 时跳过 ,计算 时先以 为起点dfs再dfs其它点。
总复杂度:
等等?排序呢???,所以可以用各种 排序算法,比如计数排序。
值得注意的是,vector/前向星常数可能较大。由于每个点最多只连两条边,可以用两个数组分别存向左/向右的边。同时最好不要用vector/前向星来作为桶排序的容器。
当然,
ctr非常良心,实测前向星存图+前向星桶排只需,是可过的。两个数组存图+std::sort也只需 。参考代码:
#include <cstdio> #include <cstring> const int N=2000010; void dfs(int u); unsigned long long seed; int n, m, c, mfq, mind, maxd, k, w[2000001], d[2000001]; int sta[N],top,tot,ans[2][N],l[N],r[N],ord[N],cnt[N]; bool vis[N]; inline int randInt() { seed = 99999989 * seed + 1000000007; return seed >> 33; } void generate() { for (int i = 1; i <= n; i++) { w[i] = randInt() % n; } for (int i = 1; i <= n; i++) { d[i] = randInt() % (maxd - mind + 1) + mind; } } void getOperation(int lastans, int &opt, int &x) { if ((0ll + randInt() + lastans) % mfq) { opt = 1; } else { opt = 2; } x = (0ll + randInt() + lastans) % n; } int main() { int i,j,lxl; scanf("%d %d %d", &n, &m, &c); scanf("%llu %d %d %d %d", &seed, &mind, &maxd, &mfq, &k); generate(); for (int i = 1; i <= k; i++) { int p, t; scanf("%d %d", &p, &t); d[p] = t; } lxl=w[c]; //lxl表示当前绫小路的能力值 for (i=1;i<=n;++i) //连边 { while (top&&sta[top]+d[sta[top]]<i) { --top; } if (top) { l[i]=sta[top]; } sta[++top]=i; } top=0; for (i=n;i>=1;--i) { while (top&&sta[top]-d[sta[top]]>i) { --top; } if (top) { r[i]=sta[top]; } sta[++top]=i; } for (i=1;i<=n;++i) //计数排序 { ++cnt[w[i]]; } for (i=n-1;i>=0;--i) { cnt[i]+=cnt[i+1]; } for (i=1;i<=n;++i) { ord[--cnt[w[i]]]=i; } for (i=n-1,j=0;i>=0;--i) //计算ans[0][i] { while (j<n&&w[ord[j]]==i) { if (ord[j]!=c) { dfs(ord[j]); } ++j; } ans[0][i]=tot; } tot=0; memset(vis,false,sizeof(vis)); dfs(c); for (i=n-1,j=0;i>=0;--i) //计算ans[1][i] { while (j<n&&w[ord[j]]==i) { if (ord[j]!=c) { dfs(ord[j]); } ++j; } ans[1][i]=tot; } int lastans = 0, finalans = 0; for (i = 1; i <= m; i++) { int opt, x; getOperation(lastans, opt, x); if (opt == 1) { finalans = (finalans * 233ll + ans[lxl>=x][x]) % 998244353; lastans = ans[lxl>=x][x]; } else { lxl=x; } } printf("%d\n", finalans); return 0; } void dfs(int u) { if (vis[u]||u==0) { return; } vis[u]=true; ++tot; dfs(l[u]); dfs(r[u]); } -
- 1
信息
- ID
- 3983
- 时间
- 3000ms
- 内存
- 250MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者