题解 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}\)

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号