YACS 2022年11月月赛 乙组 T1 数对统计 题解

题目链接

好久没更了,闲话一句,我的初赛成绩只有 71.576 才能进 NOIP,所以就更一篇吧

首先先考虑暴力算法,枚举两个数,设这两个数为 xy

如果 f[x][y]=false,那就标记为 trueans++

这种方法可以优化,怎么优化呢?

假如一个序列里出现了好几个 x,但是和 x 能构成序对的只有两种情况:

x 在左边,另一个在右边

x 在右边,另一个在左边

这样我们仅需要把 x 出现的第一次,最后一次记录下来,

然后统计最右边的 x 左边可以构成多少,最左边的 x 右边可以构成多少

可以构成多少就是有多少不重复的,数字范围很小,开桶即可

容易证明,这两个构造的数对最多只有一个一样,即 xxxx

如果 x 出现的次数大于 1 次那么就会产生这个重复,

减一即可,然后除以二(xyyx 重算)

再优化,想到我们只统计 x 最后一次出现的左边有多少不一样的即可。

或者第一次出现的右边,这里取最后一次出现的左边(比较方便)

先证明为啥是对的,这样肯定能统计到 yx,那么 xy 呢?

答:会在 y 的回合被统计

离线乱搞,把区间排序之后再算,离线 O(n)+ 排序 O(nlogn) 搞定

代码:

复制代码
#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;
}
复制代码
posted @   Xy_top  阅读(137)  评论(6编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示