1 条题解
-
0
这啥唐题。
考虑 怎么做。把序列劈成左右两半,分别问两边,这样可以得到两个元素都在左半区间/右半区间的集合个数。还要计算一个在左半边,另一个在右半边的集合个数。容易想到把序列劈成 份,左半边有 个,右半边也有 个,从左右各选一个小区间拼在一起查询,然后再容斥减去两个元素都在小区间内的部分即可。
扩展到 的情况。考虑把序列平均分成 份,查询从中任选 个小区间拼在一起的答案。这样会算重,需要容斥一下。从大到小考虑小区间个数 :
- :落在 个小区间内的集合会被恰好计算 次,容斥系数为 。
- :只落在 个小区间内的集合会在 时被计算 次(两个区间固定,剩下一个区间任选),因此 ,解得 。
- :只落在 个小区间内的集合会在 时被计算 次,在 时被计算 次,因此 ,解得 。
询问次数为 次,刚好卡满。
:::success[代码]
#include <bits/stdc++.h> using namespace std; int query(vector<int>); int solve(int N) { vector<int> vec[6]; int q = N / 6, r = N % 6, cur = 0; for (int i = 0; i < 6; ++i) { int cnt = q + (i < r); for (int j = 0; j < cnt; ++j) vec[i].emplace_back(cur++); } int res = 0; for (int i = 0; i < 6; ++i) for (int j = i + 1; j < 6; ++j) for (int k = j + 1; k < 6; ++k) { vector<int> qr; for (int x : vec[i]) qr.emplace_back(x); for (int x : vec[j]) qr.emplace_back(x); for (int x : vec[k]) qr.emplace_back(x); res += query(qr); } for (int i = 0; i < 6; ++i) for (int j = i + 1; j < 6; ++j) { vector<int> qr; for (int x : vec[i]) qr.emplace_back(x); for (int x : vec[j]) qr.emplace_back(x); res -= query(qr) * 3; } for (int i = 0; i < 6; ++i) res += query(vec[i]) * 6; return res; }:::
- 1
信息
- ID
- 9664
- 时间
- 3000ms
- 内存
- 2048MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者