哞叫时间Ⅱ
题目链接:https://www.acwing.com/problem/content/description/6137/
题意:
给定一个长度为n的数组,求出三个数ai,ap,aq(ai!=ap,ap=aq)(i<p<q)的种类数量
思路:
时间复杂度需O(n),因此程序只能有一重循环搞定
不妨从后向前遍历,如果一个数字出现次数==两次,让计数器k++。
由于我们需要种类不能重复,且要满足122式的条件。所以用res记录(i,n】的出现次数大于等于2的数字总数,用ai去配。
那么不难发现,如果ai本身出现大于等于2次,需要将ai ai ai这种情况剔除一次,如果ai遍历过了,那么只需要看现在遍历的位置和ai上次出现位置之间,有哪些新的数出现次数大于等于2次加上去即可
可能表达的不是很清楚,希望代码更容易让人懂一些
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define pb push_back
#define int long long
#define endl "\n"
#pragma GCC optimize(3)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const ll llmax=LLONG_MAX;
const int maxn=1e6+5;
const int mod=1e9+7;
int n;
int a[maxn];
int tot[maxn];
int ans;
int res[maxn];
int k;
bool vis[maxn];
pii pos[maxn];
signed main()
{
ios::sync_with_stdio(false),cin.tie(0);
cin>>n;
rep(i,1,n) cin>>a[i];
for(int i=n;i>=1;i--){
tot[a[i]]++;
res[i]=k;
if(tot[a[i]]==2){
k++;
}
if(i<=n-2){
if(!vis[a[i]]){
ans+=res[i];
if(tot[a[i]]>2&&pos[a[i]].second==0){
ans--;
pos[a[i]].second=1;
}
vis[a[i]]=true;
pos[a[i]].first=i;
}else{
ans+=(res[i]-res[pos[a[i]].first]);
if(tot[a[i]]>2&&pos[a[i]].second==0){
ans--;pos[a[i]].second=1;
}
pos[a[i]].first=i;
}
}
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号