题解 CF1004C

题意描述:

给定 \(n\) 个数,从前往后找,看看能和后面的数组成多少个不同的数对。

若两个数对仅仅是位置不同,我们也认为是两个不同的数对。

题目分析:

阅读题目,我们不难看出,若前面有一个数已经出现了,后面即使出现了重复的数,在以那个重复的数为开头时也不会被统计答案。

故我们易得以下思路:

维护两个 map 和一个 set 分别维护的是:每个数出现了多少次、是否出现过以某数为开头的情况和当前数的种类数。

然后我们从前往后扫,遇到一个数将其从第一个 map 中删去一次,若删除后第一个 map 关于这个数的信息为 \(0\),则将其从 set 中删除。然后若该数在第二个 map 中被标记,则证明已经出现过以该数为开头的情况,否则将答案加上当前 set 的大小。

时间复杂度 \(O(n \lg n)\)

代码实现:

#include <bits/stdc++.h>
#define dbg(x) cerr<<#x<<": "<<x<<endl;
#define int long long
#define TIME_LIMIT 1
using namespace std;
#define MAX_SIZE (int)1.1e5
typedef pair<int,int> pii;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

map<int,int>backet;
set<int>bbs;
map<int,bool>hashtable;

int a[MAX_SIZE];

signed main(){
    ios::sync_with_stdio(false);
#ifdef LOCAL
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
    double c1 = clock();
#endif
//============================================
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        bbs.insert(a[i]);
        backet[a[i]]++;
    }
    int ans = 0;
    for(int i=1;i<=n;i++){
        backet[a[i]]--;
        if(!backet[a[i]]){
            auto it = bbs.find(a[i]);
            bbs.erase(it);
        }
        if(!hashtable[a[i]])
            hashtable[a[i]] = true;
        else
            continue;
        ans += bbs.size();
    }
    cout<<ans<<endl;
//============================================
#ifdef LOCAL
    double c2 = clock();
    cerr<<"Used Time: "<<c2-c1<<" μs."<<endl;
    if(c2-c1>TIME_LIMIT*CLOCKS_PER_SEC)
        cerr<<"Warning!! Time Limit Exceeded!!"<<endl;
    fclose(stdin);
    fclose(stdout);
#endif
    return 0;
}

\(\text{Written on Ubuntu 22.10}\)

posted @ 2023-02-16 16:51  Larry76  阅读(25)  评论(0)    收藏  举报