Time Limit: 2 sec / Memory Limit: 1024 MiB
Score : 425 points
Problem Statement
You are given an integer sequence A=(,
,...,
) of length N.
Find the number of triples of integers (i,j,k) that satisfy all of the following:
- 1≤i,j,k≤N
:
:
=7:5:3
- min(i,j,k)=j or max(i,j,k)=j.
Constraints
- All input values are integers.
- 1≤N≤
- 1≤Ai≤
Input
The input is given from Standard Input in the following format:
N
…
Output
Output the answer.
Sample Input 1
cpp
10
3 10 7 10 7 6 7 6 5 14
Sample Output 1
7
The seven triples of integers (i,j,k) that satisfy the conditions are:
- (3,9,1)
:
:
=7:5:3, and max(i,j,k)=j.
- (5,9,1)
:
:
=7:5:3, and max(i,j,k)=j.
- (7,9,1)
:
:
=7:5:3, and max(i,j,k)=j.
- (10,2,6)
:
:
=14:10:6=7:5:3, and min(i,j,k)=j.
- (10,2,8)
:
:
=14:10:6=7:5:3, and min(i,j,k)=j.
- (10,4,6)
:
:
=14:10:6=7:5:3, and min(i,j,k)=j.
- (10,4,8)
:
:
=14:10:6=7:5:3, and min(i,j,k)=j.
Sample Input 2
cpp
6
210 210 210 210 210 210
Sample Output 2
0
Sample Input 3
cpp
21
49 30 50 21 35 15 21 70 35 9 50 70 21 49 30 50 70 15 9 21 30
Sample Output 3
34
考察点
1.数据统计与哈希映射
需要统计每个值在序列中的出现位置,由于值域很大(1≤Ai≤),但序列长度有限(1≤N≤
),使用哈希表将每个值映射到其索引列表是高效的选择。
cpp
unordered_map<int,vector<int>>pos;
for(int i=0;i<n;i++){
cin>>a[i];
pos[a[i]].push_back(i+1);
}
2.条件转化与枚举优化
比例条件 :
:
=7:5:3 转化为 存在正整数t,使得
=7t、
=5t、
=3t。
通过枚举中间值5t(即)来减少枚举量:只需检查每个是5的倍数的值,计算对应的7t和3t是否存在于序列中。
cpp
for(int j=1;j<=n;j++){
int val=a[j-1];
if(val%5)continue;
int t=val/5;
int val3=t*3,val7=t*7;
/****************************/
}
3.索引条件处理
条件 min(i,j,k)=j 或 max(i,j,k)=j 意味着 j 必须是三个索引中最小值或最大值。
这转化为对于每个候选的 j(对应值5t),分别计算:
当j最小时:统计值7t的索引中大于j的数量,以及值3t的索引中大于j的数量,两者乘积即为贡献。
当j最大时:统计值7t的索引中小于j的数量,以及值3t的索引中小于j的数量,两者乘积即为贡献。
4.二分查找加速
由于索引列表有序,对于每个j,需要在另外两个值的索引列表中快速查询大于或小于j的元素个数。使用二分查找可以将每次查询的复杂度降至O(log n),确保整体效率。
cpp
vector<int>&pos3=pos[val3];
vector<int>&pos7=pos[val7];
//情况一:max(i,j,k)=j
auto p3=lower_bound(pos3.begin(),pos3.end(),j);
auto p7=lower_bound(pos7.begin(),pos7.end(),j);
ll c=p3-pos3.begin(),d=p7-pos7.begin();
ans+=c*d;
//情况2:min(i,j,k)=j
p3=upper_bound(pos3.begin(),pos3.end(),j);
p7=upper_bound(pos7.begin(),pos7.end(),j);
c=pos3.end()-p3,d=pos7.end()-p7;
ans+=c*d;
5.复杂度控制
整体算法的时间复杂度为O(N log N),适合1≤N≤。关键在于避免暴力枚举三元组,而是通过枚举中间值、利用哈希表和二分查找来高效计数。
代码
(要点已注释)
cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n;
cin>>n;
vector<int>a(n);
unordered_map<int,vector<int>>pos;
for(int i=0;i<n;i++){
cin>>a[i];
pos[a[i]].push_back(i+1);
}
ll ans=0;//长整型防止溢出
for(int j=1;j<=n;j++){
int val=a[j-1];
if(val%5)continue;
int t=val/5;
int val3=t*3,val7=t*7;
vector<int>&pos3=pos[val3];//注意:是引用,而不是拷贝(vector<int>pos3=pos[val3],会超时)
vector<int>&pos7=pos[val7];
//情况一:max(i,j,k)=j
auto p3=lower_bound(pos3.begin(),pos3.end(),j);
auto p7=lower_bound(pos7.begin(),pos7.end(),j);
ll c=p3-pos3.begin(),d=p7-pos7.begin();
ans+=c*d;
//情况2:min(i,j,k)=j
p3=upper_bound(pos3.begin(),pos3.end(),j);
p7=upper_bound(pos7.begin(),pos7.end(),j);
c=pos3.end()-p3,d=pos7.end()-p7;
ans+=c*d;
}
cout<<ans;
return 0;
}