河南省第十三届大学生程序设计竞赛热身赛 C
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了河南省第十三届大学生程序设计竞赛热身赛 C相关的知识,希望对你有一定的参考价值。
2021年河南省第十三届icpc大学生程序设计竞赛热身赛 C
题意:
给定一个序列,求所有不相同的子序列的个数,要求子序列的长度必须为3
样例:
输入:
6
1 2 3 1 2 3
输出:
17
输入:
4
1 4 4 2
输出:
3
- 思路:
- 维护三个数组
- l[i]代表 a i a_i ai左边出现的不同数的个数
- r[i]代表 a i a_i ai右边不同数的个数
- last[i]代表上一个出现a[i]的下标
固定中间的位置,从前往后开始枚举每个数,对于当前数作为中间数贡献的结果为 这个数前面的不同数的个数乘上这个数后面的不同数的个数,但是考虑到可能后面会出现相同的数,前面已经算出了一些结果,就会算重一部分,所以每次不同的数要减去上一个此数的下标位置左面的不同数的个数(即 l[last[i]])
例:
1 2 3 4 5 3 6
当第一个3作为中间的数时,1和2作为第一个位置已经算进结果里面了,所以下次到3时不能把1和2作为第一个位置,所以第一个位置结果数为l[i]-l[last[i]],也就是3,4,5共3个数(5-2)后面直接乘上a[i]后面不同数的个数,因为前面的数已经不同了,所以后面的数不需要处理了,就算有重复,第一个位置不同,最后的三元子序列就不同。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+5;
int a[N],l[N],r[N],last[N];
ll ans;
int main()
{
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
map<int,int>mp;
int cnt=0;
for(int i=1;i<=n;i++)
{
l[i] = cnt;
if(!mp[a[i]]) ++cnt;
mp[a[i]]++;
}
mp.clear();cnt=0;
for(int i=n;i>=1;i--)
{
r[i] = cnt;
if(!mp[a[i]])++cnt;
mp[a[i]]++;
}
mp.clear();
for(int i=1;i<=n;i++)
{
if(mp[a[i]]) last[i]=mp[a[i]];
else last[i]=0;
mp[a[i]]=i;
}
for(int i=1;i<=n;i++)
ans+=(l[i]-l[last[i]])*r[i];
cout<<ans<<'\\n';
return 0;
}
以上是关于河南省第十三届大学生程序设计竞赛热身赛 C的主要内容,如果未能解决你的问题,请参考以下文章
2021河南省第十三届ICPC大学生程序设计竞赛 A.祝融传火(暴力,签到)