专栏文章
题解:P2119 [NOIP 2016 普及组] 魔法阵
P2119题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @mipvd8f6
- 此快照首次捕获于
- 2025/12/03 18:33 3 个月前
- 此快照最后确认于
- 2025/12/03 18:33 3 个月前
solution
一道数学推导优化枚举的题。
容易写出暴力枚举,考虑通过缩小枚举范围优化枚举。
知道 且 。
设一个参数 ,对原式变形得 和 ,即 和 。

对于每个 , 到 、 到 的距离都是定值,而 到 的距离是个区间。
首先要了解这点。若 且,并且 ,即 和 可以组成魔法阵,那么 ,也就是 和 一定可以组成魔法阵。
类似的,若 且,并且 ,即 和 可以组成魔法阵,那么 ,也就是 和 一定可以组成魔法阵。
我们从后往前枚举 ,记 表示 出现次数,乘法原理得当前可以作为 的个数为 ,用一个后缀和维护 变枚举边算,这样就可以 做了。
从前往后枚举 ,维护前缀和,同样可以算出贡献。
那就得到了做法,先枚举 ,再分别枚举 和 的范围计算贡献。
的范围是 到 。当 且 时 最大。
的范围是 到 。当 且 时 最小。
这道题还是有点抽象,不太好描述,可以结合代码体会。
code
CPP#include <bits/stdc++.h>
using namespace std;
int n, m, A[50005][4], x[50005], num[50005];
int main () {
cin >> n >> m;
for (int i=1; i<=m; ++i)
cin >> x[i],
num[x[i]]++;
for (int k=1, a, b, c, d, s; 9*k<=n; ++k) {
for (a=n-9*k-1, s=0; a>=1; --a) // 枚举a,确定bcd
b=a+2*k, c=b+6*k+1, d=c+k,
s+=num[c]*num[d],
A[a][0]+=num[b]*s,
A[b][1]+=num[a]*s;
for (d=9*k+2, s=0; d<=n; ++d) // 枚举d,确定abc
a=d-9*k-1, b=a+2*k, c=d-k,
s+=num[a]*num[b],
A[c][2]+=num[d]*s,
A[d][3]+=num[c]*s;
}
for (int i=1; i<=m; ++i, cout << '\n')
for (int j=0; j<4; ++j)
cout << A[x[i]][j] << ' ';
return 0;
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...