Logo lxn 的博客

博客

ARC170B - Arithmetic Progression Subsequence

...
lxn
2025-12-01 12:57:46

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2024-01-22 19:32:56

  • 题目大意

给定一个长度为$n$的序列,如果区间 $[L,R]$ 中存在 $L \leq i<j<k\leq R$ ,使得 $a_i-a_j=a_j-a_k$ 成立,则这个区间为好区间。问共有多少个好区间。

  • 题目分析

为了不重不漏的统计,我们限定右端点 $k$ ,去找符和要求的左端点 $left$ 。 找出符要求的 $i,j,k$ ,可以发现 $a_i,a_j,a_k$ 构成等差数列,数据的范围是 $1...10$ ,符合要求的的情况为 $1,5,9$ ; $10, 6,2$ 等。可以推导出公差的范围为 $-4..4$ .

已知 $a_k$ ,枚举公差,找到符合要求的前两项的值,设数组 $mp[i][j]$ 存储符合要求的最近数值。找到以 $k$ 为结束点的最近 $left$。

如何去维护 $mp[i][j]$ 呢?对于当前点 $k$ 来说,只会改变与 $mp[i][a_k]$ 相关的数据,$mp[i][a_k]=( i$ 出现的最后位置 $)$ 。因此我们还需要用一个桶记录这个位置。

再维护一个 $left$ 的前缀 $max\_left$ ,那么答案就是不断累加从 $1$号结点到 $max\_left$ 的值,也就是 $ans+=max\_left$ 。

时间复杂度为 $O(N \times 10)$ 。

  • 参考代码
#include <bits\/stdc++.h>
using namespace std;
#define int long long
int n;
int a[100005];
int mp[11][11],l[11];
signed main(){
	
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	
	int ans=0,lf=0,mlf=0;
	\/\/对每一个右端点q,找其符合要求的最近左端点lf,和前缀最大左端mlf点比较  ans+=mlf
	for(int k=1;k<=n;k++) {
		for(int d=-4;d<=4;d++){\/\/枚举公差 
			if(a[k]+2*d>=1&&a[k]+2*d<=10)lf=max(lf,mp[a[k]+2*d][a[k]+d]);
			mlf=max(mlf,lf);
		}
		ans+=mlf;
		for(int i=1;i<=10;i++){
			if(l[i])mp[i][a[k]]=l[i];
		}
		l[a[k]]=k;	
	}
	
	cout<<ans<<endl;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。