cf Sonya and Robots
题目网址点击打开链接
题目意思是给你一个序列,要从左边数起第一个a的位置要在从右边数起第一个b的位置的前面,让你求(a,b)这样的一对数的种数是多少。
序列里的每个数都可以和他后面的全部数组成(a,b),但是有重复。重复分2种,一种是(2,3,3)这种情况,可以组成2个(2,3),但是有重复就只算1种,要避免这种情况就要维护每一个数字后面数的种类。一种是(3,3,2)这种情况,可以组成(3,3)和(3,2)和(3,3)但是有重复只算2种,要避免这种情况就要用vis数组,假如一个数已经做过一次a了,那么下次就不能做a了。做法就是对这个序列进行桶排序,但并不是获取这个序列的升序或减序序列,是要记录下这个序列的每种数的个数,以及这个序列的数的种数,另外还设了一个标记数组标记哪些数字做过a了。
从头到尾扫一遍,用cnt维护该数字后面的数的种类,然后cnt即是该数字可以和后面的数组成(a,b)的种数,然后判断一下该数字是否做过a了,做过了的话就跳过该数字,若是没做过就ans+=cnt,然后给该数组标记。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,a[maxn],t[maxn],vis[maxn];//t数组表示桶数组
int main()
{
long long cnt=0,ans=0;
cin>>n;
for(int i=0;i<n;i++)//桶排序,在桶排序的过程中统计序列中有多少种数
{
cin>>a[i];
if(t[a[i]]==0)
{
cnt++;
}
t[a[i]]++;
}
for(int i=0;i<n;i++)
{
t[a[i]]--;
if(t[a[i]]==0) cnt--;
if(!vis[a[i]])
{
ans+=cnt;
vis[a[i]]=1;
}
}
cout<<ans<<endl;
return 0;
}