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

fighter
**搬运于
2025-08-24 22:16:27,当前版本为作者最后更新于2020-01-30 09:40:20,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
发现,那么我们自然想到预处理之后回答询问。
先考虑一个更简单的问题,如果表示在区间中,满足的的数量,那么我们是可以枚举左右端点,用一个桶做到预处理的。
那么与最后的答案是什么关系呢?最后要求的是:在一段区间内,左右端点不强制选的方案数。这隐隐约约的有点像是数组的一个前缀和。
我们可以考虑先求出表示左端点在内,右端点在内的总方案数。这就真的是的二位前缀和了。
可以这么理解,把对应到平面上的一个点,那么就是从到的这个矩形中所有点的和。这样我们也就可以在的时间内求出。
同样的,最后的答案实际上是区间左右端点都在内总答案。对应到平面上也就是左上角为,右下角为的矩形中所有点的和。这样就可以通过来求答案了。
代码
注意开桶的时候需要平移值域
#include <bits/stdc++.h> #define ll long long #define MAX 5005 #define K 1000000 using namespace std; int n, Q; int a[MAX], cnt[2000005]; ll s[MAX][MAX]; int main() { cin >> n >> Q; for(int i = 1; i <= n; ++i){ scanf("%d", &a[i]), a[i] += K; } for(int i = 1; i <= n; ++i){ for(int j = i+1; j <= n; ++j){ if(j > i+1){ if(a[i]+a[j] <= K*3 && a[i]+a[j] >= K) s[i][j] = cnt[K*3-a[i]-a[j]]; } cnt[a[j]]++; } for(int j = i+1; j <= n; ++j){ cnt[a[j]]--; } } for(int i = 1; i <= n; ++i){ for(int j = 1; j <= n; ++j){ s[i][j] += s[i-1][j]+s[i][j-1]-s[i-1][j-1]; } } int l, r; while(Q--){ scanf("%d%d", &l, &r); printf("%lld\n", s[r][r]-s[l-1][r]-s[r][l-1]+s[l-1][l-1]); } return 0; }
- 1
信息
- ID
- 5022
- 时间
- 2000ms
- 内存
- 250MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者