打卡信奥刷题(3364)用C++实现信奥题 P9661 [ICPC 2021 Macao R] Sandpile on Clique
P9661 [ICPC 2021 Macao R] Sandpile on Clique
题目描述
阿贝尔沙堆模型(Abelian Sandpile Model)是一个著名的显示自组织临界性的动力学系统。自从它由 Per Bak、Chao Tang 和 Kurt Wiesenfeld 在 1987 年的一篇论文中引入以来,它已经被研究了数十年。沙堆模型的预测引起了物理学、计算机科学和数学的广泛关注,这不仅是因为它美丽的代数结构,还因为它与负载平衡和内部扩散有关的模型的应用,如去随机化。沙堆模型与许多其他模型和物理现象相关,如转子路由模型、雪崩模型。
在沙堆模型中,给定一个顶点编号从 1 1 1 到 n n n 的无向图 G G G。我们还给出了 n n n 个整数 a 1 , a 2 , ⋯ , a n a_1, a_2, \cdots, a_n a1,a2,⋯,an,其中 a i a_i ai 表示初始时放置在顶点 i i i 上的筹码数量。每个回合,我们将选择一个任意的顶点 v v v,使得 v v v 上的筹码数量不小于与 v v v 相连的边数,记为 d v d_v dv。对于 v v v 的每个邻居,它将从 v v v 接收一枚筹码。因此, v v v 将失去 d v d_v dv 枚筹码。这个过程被称为 firing 或 toppling。直到没有顶点 v v v 至少有 d v d_v dv 枚筹码时,firing 才会停止。
可以证明,firing 的顺序不会影响结果。同时,也可能 firing 永远不会终止。这种情况被描述为“recurrent”。现在给定一个团和初始筹码数量,请确定这个实例是否是一个 recurrent 实例。如果不是,请分别输出每个节点的最终筹码数量。
团(也称为完全图)是一个图,其中任意两个顶点都有边相连。
输入格式
每个测试文件中只有一个测试用例。
输入的第一行包含一个整数 n n n( 2 ≤ n ≤ 5 × 10 5 2 \leq n \leq 5 \times 10^5 2≤n≤5×105),表示团的大小。
第二行包含 n n n 个整数 a 1 , a 2 , ⋯ , a n a_1, a_2, \cdots, a_n a1,a2,⋯,an( 0 ≤ a i ≤ 10 9 0 \leq a_i \leq 10^9 0≤ai≤109),其中 a i a_i ai 表示放置在顶点 i i i 上的初始筹码数量。
输出格式
输出一行。如果给定的沙堆实例将终止,则输出由空格分隔的 n n n 个整数,其中第 i i i 个整数表示第 i i i 个顶点上的最终筹码数量。否则输出 Recurrent(不包括引号)。
请不要在每行末尾输出额外的空格,否则您的解决方案可能被认为是错误的!
【样例解释】
对于第一个样例测试用例:
- 我们只能在开始时选择顶点 1 1 1。筹码数量变为 { 1 , 1 , 4 , 1 , 4 } \{1, 1, 4, 1, 4\} {1,1,4,1,4}。
- 现在我们可以选择顶点 3 3 3 或 5 5 5,因为它们都至少有 4 4 4 枚筹码。我们选择顶点 3 3 3,筹码数量变为 { 2 , 2 , 0 , 2 , 5 } \{2, 2, 0, 2, 5\} {2,2,0,2,5}。选择顶点 5 5 5 会得到相同的结果。
- 现在我们选择顶点 5 5 5。筹码数量变为 { 3 , 3 , 1 , 3 , 1 } \{3, 3, 1, 3, 1\} {3,3,1,3,1}。没有顶点至少有 4 4 4 枚筹码,因此 firing 终止。
对于第二个样例测试用例,我们可以重复选择顶点 1 1 1 和 2 2 2。firing 永远不会终止。
翻译来自于:ChatGPT
输入输出样例 #1
输入 #1
5
5 0 3 0 3
输出 #1
3 3 1 3 1
输入输出样例 #2
输入 #2
2
1 0
输出 #2
Recurrent
C++实现
#include <iostream>
#include <cstdio>
const int N = 500005;
int a[N], qz[N];
bool vis[N];
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for(int i = 1; i <= n; ++i) {
qz[0] += a[i] / n;
int t = (a[i] / n + 1) * n - a[i];
qz[t]++;
vis[t - 1] = true;
}
int s = 0, v = -1;
for(int i = 0; i < n; ++i) {
s += qz[i];
if(s == i && vis[i] == false) {
v = i;
break;
}
}
if(v == -1)
printf("Recurrent");
else {
for(int i = 1; i <= n; ++i)
printf("%d ", (a[i] + v) % n);
}
return 0;
}

后续
接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)