題意
題解
發現,那麼我們自然想到預處理之後回答詢問。
先考慮一個更簡單的問題,如果表示在區間中,滿足的的數量,那麼我們是可以枚舉左右端點,用一個桶做到預處理的。
那麼與最後的答案是什麼關係呢?最後要求的是:在一段區間內,左右端點不強制選的方案數。這隱隱約約的有點像是數組的一個前綴和。
我們可以考慮先求出表示左端點在內,右端點在內的總方案數。這就真的是的二位前綴和了。
可以這麼理解,把對應到平面上的一個點,那麼就是從到的這個矩形中所有點的和。這樣我們也就可以在的時間內求出。
同樣的,最後的答案實際上是區間左右端點都在內總答案。對應到平面上也就是左上角爲,右下角爲的矩形中所有點的和。這樣就可以通過來求答案了。
代碼
注意開桶的時候需要平移值域
#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;
}