题目描述
\(T\) 组数据,每组数据给定 \(n\),\(k\),\(q\) 和一个长度为 \(n\) 的数组 \(a\),求 \(a\) 中长度大于等于 \(k\) 且最大值小于等于 \(q\) 的序列个数。
\(\sum{n}\le 2e5\)。
题目解析
- 解法一:数据结构解法
显然可以利用数据结构维护。考虑ST表预处理出区间最大值枚举区间左右端点累计,复杂度 \(O(nlogn+n^2)\),需要优化。
再想想,若区间 \([i,j]\) 符合条件,则对于每个 \(i\le k\le j\),区间 \([i,k]\) 都符合条件;若区间 \([i,j]\) 不符合,则对于每个 \(j<k\le n\),区间 \([i,k]\) 都不符合,答案可二分。所以我们枚举左端点,二分右端点,复杂度 \(O(Tnlogn)\)。
- 解法二:数学解法
显然:一个区间符合条件,当且仅当此区间不存在一个 \(i\in [i,j]\) 使 \(a_i>q\)。所以处理每一个 \(a_i>q\) 的 \(i\),统计区间长度。区间长度为 \(m\) 的合法区间贡献即为 \(\sum_{i=1}^{m}i\)。而这个式子可以预处理,复杂度 \(O(N+Tn)\)。
代码实现
因为 \(\sum{n}\le 2e5\),所以答案需要 long long。
- 解法一
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long
const int N=2e5+10;
int T;
int n,k,q;
ll f[N][31];
inline long long maxx(int l,int r){
int len=log(r-l+1)/log(2);
return max(f[l][len],f[r-(1<<len)+1][len]);
}
int main(){
scanf("%d",&T);
while(T--){
ll ans=0;
scanf("%d%d%d",&n,&k,&q);
for(int i=1;i<=n;++i) scanf("%lld",&f[i][0]);
for(int i=1;i<=30;++i)
for(int j=1;j+(1<<(i-1))-1<=n;++j)
f[j][i]=max(f[j][i-1],f[j+(1<<(i-1))][i-1]);
for(int i=1;i+k-1<=n;++i){
int l=i+k-1,r=n;
while(l<r){
int mid=(l+r+1)>>1;
if(maxx(i,mid)<=q) l=mid;
else r=mid-1;
}
if(maxx(i,l)<=q) ans+=min(l,n)-i-k+2;
}
printf("%lld\n",ans);
}
return 0;
}
- 解法二
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long
const int N=2e5+10;
int T;
int n,k,q;
ll a[N],sum[N];
int main(){
scanf("%d",&T);
for(int i=1;i<=N-10;++i) sum[i]=sum[i-1]+i;
while(T--){
ll ans=0,p=0;
scanf("%d%d%d",&n,&k,&q);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
for(int i=1;i<=n;++i){
if(a[i]>q){
if(p>=k) ans+=sum[p-k+1];
p=0;
}
else ++p;
}
if(p>=k) ans+=sum[p-k+1];
printf("%lld\n",ans);
}
}
完结撒花qwq
标签:CF1840C,int,题解,sum,long,区间,include,解法 From: https://www.cnblogs.com/Mr-KaYa/p/17488958.html