原题链接:Beauty Values
题意:给你一个序列,让你求出 所有子区间的不同数字的个数 总和
思路:或许有人跟我一样第一时间想到主席数这类的统计区间不同数个数(..好吧就当我这样),然而看到榜上过了那么多人在怎么说也不会再往那边想了,肯定是有规律的。
我在分析这个区间不同个数的时候发现某个数对区间的贡献范围。比如样例中 1 2 1 3 我们会发现 第二个 1 在区间[2,4]以及其子区间在统计个数的时候算一个贡献
即在其距离左右两端的相同的数字的大区间内算一个贡献(其他区间的1不会影响) ,然后我们这样思考后会发现如果更大的区间,比如[1,4]应该算谁的贡献。
实际上我们可以算作区间最左或者最右的值产生的贡献。我们固定一个按最左来产生贡献(这样不会重复统计)
即某个位置pos的值产生贡献区间范围在[i+1,n] (i为上一个出现的位置,n为长度)。 然后计算 子区间个数。我们这样看 1 2 1 3 上计算 第二个1 的贡献值即[2,4], [2,3],[3,4],[3,3]
所以我们发现即时左边断点在[i+1,pos]之间右边端点在[pos,n]之间。所以最后 我们可以得到关系式:( pos - i ) * (n - pos + 1)//这里下标我是从1开始记录,左端点设为0
像我这种菜鸡估计才会把这么简单的题写详细题解吧...TAT
code:
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn = 1e5+5; ll arr[maxn]; int cur[maxn]; ll ans; int main(){ int n; cin>>n; for(int i=1;i<=n;i++){ cin>>arr[i]; } ll L; ans = 0; memset(cur,0,sizeof(cur)); for(int i=1;i<=n;i++){ ans += (ll)(i-cur[arr[i]]) * (n-i+1); cur[arr[i]] = i; } cout<<ans<<endl; return 0; }