好久没更了,闲话一句,我的初赛成绩只有 $71.5$,$76$ 才能进 $NOIP$,所以就更一篇吧
首先先考虑暴力算法,枚举两个数,设这两个数为 $x$ 和 $y$,
如果 $f[x][y]=false$,那就标记为 $true$,$ans ++$
这种方法可以优化,怎么优化呢?
假如一个序列里出现了好几个 $x$,但是和 $x$ 能构成序对的只有两种情况:
$x$ 在左边,另一个在右边
$x$ 在右边,另一个在左边
这样我们仅需要把 $x$ 出现的第一次,最后一次记录下来,
然后统计最右边的 $x$ 左边可以构成多少,最左边的 $x$ 右边可以构成多少
可以构成多少就是有多少不重复的,数字范围很小,开桶即可
容易证明,这两个构造的数对最多只有一个一样,即 $xx$ 和 $xx$,
如果 $x$ 出现的次数大于 $1$ 次那么就会产生这个重复,
减一即可,然后除以二($xy$ 和 $yx$ 重算)
再优化,想到我们只统计 $x$ 最后一次出现的左边有多少不一样的即可。
或者第一次出现的右边,这里取最后一次出现的左边(比较方便)
先证明为啥是对的,这样肯定能统计到 $yx$,那么 $xy$ 呢?
答:会在 $y$ 的回合被统计
离线乱搞,把区间排序之后再算,离线 $O(n)+$ 排序 $O(n log n)$ 搞定
代码:
#include <iostream> #include <algorithm> using namespace std; int n, t, ri; int a[100005], b[100005]; int r[100005], q[100005]; long long ans, pre; int main() { cin >> n; for (int i = 1; i <= n; i ++) { cin >> a[i]; r[a[i] ] = i; } for (int i = 1; i <= 100000; i ++) if (r[i] != 0) q[++ t] = r[i] - 1; sort (q + 1, q + t + 1); for (int i = 1; i <= t; i ++) { while (ri < q[i]) { ri ++; if (b[a[ri] ] == 0) pre ++; b[a[ri] ] ++; } ans += pre; } cout << ans << endl; return 0; }标签:右边,int,题解,数对,乙组,100005,左边,统计 From: https://www.cnblogs.com/Xy-top/p/16916110.html