Hdu 5288 OO’s Sequence
链接
题意
$f(l,r): 满足a_i \% a_j \neq 0 的i的个数 (i \in [l,r],j \in [l,r],j \neq i) $
已知n个数 $a_1,a_2,…a_n$,求
$$\sum _ {i=1}^{n}\sum _ {j=i}^{n}f(i,j) \ mod \ (10^{9}+7)$$
分析
$这个题实质是对于一个包含 a_i的区间,如果a_i符合上述条件,$
$即对于a_j,a_i \% a_j \neq 0,则a_j不是a_i的因子 $
$对于每一个数 a_i,分别向左向右去找离它最近的因子的下标L[i],R[i],$
ans+=(i-L[i])*(R[i]-i);
参考代码
1 | #include<stdio.h> |
Hdu 5289 Assignment
链接
题意
一个公司有n个员工,每个员工有一个能力值a[i],
求有多少个区间满足区间内任意两个员工的能力差值小于k
分析
区间内最大差值即为区间内最大值与最小值的差
只要其差满足条件,则该区间符合条件
左区间l先固定,去找最大区间符合条件,即[l,r-1]符合 那么$ans+=\binom{r-l}{2} + r-l$
然后r不变,l不断加1,直到找到符合条件的 [l,r]为止,那么[l,j-1]会被重复算,需要减掉
为了更快的查询每个区间的最大最小值,用线段树实现的
参考代码
1 | #include<stdio.h> |
对于上述代码,在主函数中稍微改了一点,不过时间效率高一点1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46int main()
{
int T,n,k;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,n,1);
int l=1,r=1;
long long ans=0,cnt;
minA=a[1],maxA=a[1];
while(l<=n&&r<=n){
minA=min(minA,a[r]);
maxA=max(maxA,a[r]);
if(maxA-minA<k){
if(r==n){
cnt=r-l+1;
ans+=cnt*(cnt-1)/2+cnt;
}
r++;
}
else{
cnt=r-1-l+1;
ans+=cnt*(cnt-1)/2+cnt;
l++;
while(l<r){
minA=INF,maxA=-INF;
query(1,n,1,l,r);
if(maxA-minA<k)
break;
l++;
}
if(l<r){
cnt=(r-1)-l+1;
ans-=cnt*(cnt-1)/2+cnt;
r++;
}
minA=INF,maxA=-INF;
query(1,n,1,l,r);
}
}
printf("%I64d\n",ans);
}
return 0;
}