查询
Description
给出一个长度为 n n n的序列 a a a给出 q q q组询问,每组询问形如 ( x , y ) (x,y) (x,y),求 a a a序列的所有区间中,数字 x x x的出现次数与数字 y y y的出现次数相同的区间有多少个。
Data Constraint
1
<
=
n
<
=
8
∗
1
0
3
,
11
<
=
x
,
y
,
a
i
<
=
1
0
9
1<=n<=8∗10^3,11<=x,y,a_i<=10^9
1<=n<=8∗103,11<=x,y,ai<=109
题解
记录每个数字出现的位置,(由于 a [ i ] a[i] a[i]的范围是 1 0 9 10^9 109,所以我们先将数列进行离散化),对于某个询问 ( x , y ) (x,y) (x,y),我们可以将 ( x , y ) (x,y) (x,y)出现的位置序列合并并按照从小到大排序,假设合成的位置序列为 p 1 , p 2 , p 3 . . . . p_1, p_2, p_3.... p1,p2,p3....,对于答案 a n s ans ans,我们可以将答案分成 i i i类(对于x和y数量都为0的情况单独算),表示为 a n s 1 , a n s 2 . . . . . ans_1,ans_2..... ans1,ans2....., a n s i ans_i ansi。 a n s i ans_i ansi代表区间内包含的位置序列的最大值为 p i p_i pi的区间数量,那么对于每个位置 p i p_i pi,我们可以向前枚举 p i − 1 … … p 1 p_{i - 1}……p_1 pi−1……p1,只要发现 x x x和 y y y的数量相等,我们就可以用乘法原理包含此序列的区间数量加到 a n s i ans_i ansi上,最后加上 x , y x,y x,y都不存在的区间的数量,但是这样枚举复杂度是平方级别,会被卡掉,所以我们需要进行一些优化,我们可以将x出现的每个位置设置为1,y出现的每个位置设置为-1,我们按照位置序列开始模拟,我们发现对于我们所走到的位置pos,若想要某个区间 x , y x,y x,y的数量相等,那么这个区间左端点也一定是从这里出发的,所以我们可以将信息保存在该数组上,进而将答案累加起来。
#include <iostream>
#include <cstring>
#include <map>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <set>
using namespace std;
const int N = 8010, P = 131, mod = 1e9 + 7; // -_- 风气真的是差!
const double PI = 3.1415926535;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair <int, int> PII;
typedef pair <double, double> PDD;
typedef pair <LL, LL> PLL;
int a[N], ans[N][N], n, q, res[N][N];
vector <int> t, pos[N];
PII temp[(int)5e5 + 10];
int find (int x)
{
int l = 0, r = n - 1;
while (l < r)
{
int mid = l + r >> 1;
if (t[mid] >= x) r = mid;
else l = mid + 1;
}
return l;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1; i <= n; i ++) t.push_back (a[i]);
sort (t.begin(), t.end());
t.erase (unique (t.begin(), t.end()), t.end());
int len = t.size();
for (int i = 1; i <= n; i ++)
{
int x = find (a[i]);
pos[x].push_back (i);
}
//for (int i = 0; i < t.size(); i ++) pos[i].push_back (n + 1);
for (int i = 1; i <= q; i ++)
{
int x, y; cin >> x >> y;
int t1 = find (x), t2 = find (y);
temp[i] = {t1, t2};
// cout << t1 << ' ' << t2 << endl;
ans[t1][t2] = true;
}
for (int i = 0; i < n; i ++)
for (int j = 0; j < n; j ++)
if (ans[i][j])
{
int l = 0, r = 0, idx = 8010, pre = 0;
int c[16020] = {0};
vector <PII> ts;
ts.push_back ({0, 0});
while (l < pos[i].size() || r < pos[j].size())
{
if (l >= pos[i].size()) ts.push_back ({pos[j][r ++], 1});
else if (r >= pos[j].size()) ts.push_back ({pos[i][l ++], -1});
else if (pos[i][l] < pos[j][r]) ts.push_back ({pos[i][l ++], -1});
else ts.push_back ({pos[j][r ++], 1});
}
ts.push_back ({n + 1, 0});
for (int k = 0; k < ts.size(); k ++) cout << ts[k].first << ' ';
cout << endl;
for (int k = 1; k < ts.size(); k ++)
{
int d = ts[k].first - ts[k - 1].first;
res[i][j] += (d - 1) * (d - 2) / 2;
cout << (d - 1) * (d - 2) / 2 << ' ';
if (k == ts.size() - 1) break;
c[idx] += d, idx += ts[k].second;
int d1 = ts[k + 1].first - ts[k].first;
res[i][j] += d1 * c[idx]; //cout << d1* c[idx] << ' ';
}
cout << endl;
}
for (int i = 1; i <= q; i ++) printf ("%d\n", res[temp[i].first][temp[i].second]);
return 0; //652
}