CF1527C Sequence Pair Weight

博客介绍了CF1527C问题的解决方案,主要内容涉及如何计算序列中相等元素形成的连续区间的数对之和。通过分析相等数对对总和的贡献,并利用离散化技术简化处理大规模值域的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

题目大意

给定一个长度为 n n n 的序列 a a a,求:
∑ 1 ≤ l < r ≤ n ∑ l ≤ x < y ≤ r [ a x = a y ] \sum_{1\le l<r\le n}\sum_{l\le x<y\le r}[a_x=a_y] 1l<rnlx<yr[ax=ay]
即:求每一个连续区间内的相等数对之和。

Solution

套路题,如果直接求不好求,那么算每一部分的贡献。

首先考虑如果两个数 a i = a j a_i=a_j ai=aj i < j i<j i<j),那么其产生的贡献是 i × ( n − j + 1 ) i\times (n-j+1) i×(nj+1),也就是有 i × ( n − j + 1 ) i\times (n-j+1) i×(nj+1) 个区间包含它。

此时考虑如果有第三个 a k = a i = a j a_k=a_i=a_j ak=ai=aj k > j k>j k>j),这个时候贡献会加上:
i × ( n − k + 1 ) + j × ( n − k + 1 ) i\times (n-k+1)+j\times (n-k+1) i×(nk+1)+j×(nk+1)
= ( i + j ) × ( n − k + 1 ) =(i+j)\times (n-k+1) =(i+j)×(nk+1)

于是我们想到,对于每一个值,我们记录这个值的下标的和为 s u m sum sum,当这个值新加入了一个下标时,我用这个和来更新答案:
a n s = a n s + s u m × ( n − i + 1 ) ans=ans+sum\times (n-i+1) ans=ans+sum×(ni+1)
其中 i i i 为新加入的下标。

那么问题是值域比较大,所以用到离散化即可。

Code

#include<bits/stdc++.h>
#define inf 1<<30
#define INF 1ll<<60
#define ll long long
using namespace std;
const int MAXN=1e5+10;
int a[MAXN],b[MAXN];
ll sum[MAXN];
void solve(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+1+n);
	int cnt=unique(b+1,b+1+n)-b-1;
	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+cnt,a[i])-b;
	//离散化
	ll ans=0;
	for(int i=1;i<=n;i++){
		if(!sum[a[i]]) sum[a[i]]+=i;
		else{
			ans+=sum[a[i]]*(n-i+1);
			sum[a[i]]+=i;
		}
	}printf("%lld\n",ans);
	for(int i=1;i<=cnt;i++) sum[i]=0;//注意不要用 memset 全部更新,这题能卡掉(亲测)
}
int main()
{
	int T;
	for(scanf("%d",&T);T--;)
		solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值