Problem - 1527C - Codeforces
序列的权重被定义为具有相同值(ai=aj)的无序索引对(i,j)(这里i<j)的数量。例如,序列a=[1,1,2,2,1]的权重是4,具有相同值的无序索引对的集合是(1,2),(1,5),(2,5),和(3,4)。
给你一个n个整数的序列a。打印a的所有子段的权重之和。
一个序列b是一个序列a的子段,如果b可以从a中删除几个(可能是零或全部)元素的开始和几个(可能是零或全部)元素的结束而得到。
输入
每个测试包含多个测试用例。第一行包含测试用例的数量t(1≤t≤105)。测试用例的描述如下。
每个测试用例的第一行包含一个单一的整数n(1≤n≤105)。
每个测试用例的第二行包含n个整数a1,a2,...,an(1≤ai≤109)。
保证所有测试用例的n之和不超过105。
输出
对于每个测试案例,打印一个整数--a的所有子段的权重之和。
例子
inputCopy
2
4
1 2 1 1
4
1 2 3 4
输出拷贝
6
0
注意
在测试案例1中,序列[1,2,1,1]的所有可能的大小超过1的子段是。
[1,2]有0个有效的无序对。
[2,1]有0个有效的无序对。
[1,1]有1个有效的无序对。
[1,2,1]有1个有效的无序对。
[2,1,1]有1个有效的无序对。
[1,2,1,1]有3个有效的无序对。
答案是6。
在测试案例2中,序列的所有元素都是不同的。因此,没有任何一个子数的有效无序对具有相同的值。答案是0。
题解:
假如我们有n个数字
a1,a2,a3,..ai..aj...an
如果ai = aj,那么含有这两个元素的子串就是对答案有贡献的
此时的贡献应该为i * (n - j + 1)
但是如果后面又有一个ak = aj呢?
后面应该还是n - k + 1
那对于前面来说我们可以以前出现过的记录相加
f[ai] += i
每次对答案的贡献就应该是ans += f[a[i]]*(n- i + 1)
#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
#define int long long
int a[200050];
int b[200050];
void solve()
{
int n;
cin >> n;
map<int,int> f;
int ans = 0;
for(int i = 1;i <= n;i++)
{
int x;
cin >> x;
int y = n - i + 1;
ans += f[x]*y;
f[x] += i;
}
cout << ans <<"\n";
}
//101
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
int t = 1;
cin >> t;
while(t--)
{
solve();
}
}