Problem - C - Codeforces
题目大意:有一个长度为n的数组a,问有多少个子串[l,r],满足这个子串作为子序列只在a中出现过一次
1<=n<=1e5;1<=a[i]<=1e9
思路:我们发现对于从1开始的连续区间,答案都是非递减的,所以我们考察每添加一个数字,答案怎么变化,并不会影响前面的答案。
那么假如我们当前新添了一个数a[r],那么新增的合法答案计数就是a[r]为区间右端点的合法子串,也就是看1到r中有多少个l满足[l,r]是合法区间,我们发现,对于前面的一个数a[i],如果它出现了多次,那么只有第一次出现时作为区间左端点才是合法的,在后面出现时那个数都可以被第一次出现的那个数替代,所以每个位置的数的贡献也就是在它前面第一次出现的数的数量,那么每个相同的数的贡献,也就是在最后出现的那个位置之前有多少第一次出现的数。
要统计答案我们首先记录每个数最后一次出现的位置las[i],然后从左往右遍历数组,记录第一次出现的数的数量,然后如果当前数已经在这个数最后一次出现的位置,就统计这个数的贡献。
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
const int N = 1e5 + 5;
int n;
int a[N];
void init()
{}
void solve()
{map<int, int>las;cin >> n;init();for (int i = 1; i <= n; i++){cin >> a[i];las[a[i]] = i;//记录每个数字最后一次出现的次数}ll ans = 0;ll cnt = 0;set<int>vis;for (int i = 1; i <= n; i++){ if (vis.find(a[i]) == vis.end()){//第一次出现这个数字cnt++;//记录有多少个第一次出现的vis.insert(a[i]);}if (las[a[i]] == i){//当前数字是最后一次出现的位置,统计贡献ans += cnt;}}cout << ans;cout << '\n';
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);int t;cin >> t;//t = 1;while (t--){solve();}return 0;
}