2025.11.1日每日一题
标签:前缀和/二分法
语法: 注意开 long long 的答案,乘法要记得乘以 1LL
题目里提到因子,我们要把输入的 a 数列处理成相对应的因子:
大致有两种算法
第一种是暴力遍历
for(int j=1;j<N;j++){
for(int i=1;i*i<=j;i++){
if(j%i==0) now[j]+=2;
if(i*i==j) now[j]--;
}
}
如果整除的话数字就加上2,最后再判断是不是重复计算了。
第二种是类似于筛法
for(int i=1;i<=100000;i++){
for(int j=i;j<=100000;j+=i)
now[j]++;
}
把每个因子相对的倍数都加上1,一劳永逸,把全部都算出来了。
后面考虑答案
答案是在某个区间内部的数对个数,比如因子是2的有 个,那么用
来表示。
把所有因子的组数加起来就是答案。
-- btw 1e5内的因子数最多为 128
大致有两种算法
第一种:用前缀和
对于一个因子数 ,把所有的因子数为
的位置标为1,那么
里面的因子的个数就是区间内数的和,然后遍历一下因子从1到130就行。
for(int i=1;i<=n;i++){
int x;
cin>>x;
sum[i][now[x]]=1;
}
for(int i=1;i<=130;i++){
for(int j=1;j<=n;j++){
sum[j][i]=sum[j-1][i]+sum[j][i];
}
}
while(q--){
int l,r;
cin>>l>>r;
long long ans=0;
for(int i=1;i<=130;i++)
ans+=1LL*(sum[r][i]-sum[l-1][i])*(sum[r][i]-sum[l-1][i]-1)/2;
cout<<ans<<endl;
}
第二种:是用二分法
把每个因子 相对应的位置push到一个vector里面,然后用二分法看看有几个。
for(int i=1;i<=n;i++){
int x;
cin>>x;
pos[now[x]].push_back(i);
}
while(q--){
long long ans=0;
int l,r;
cin>>l>>r;
for(int i=1;i<=130;i++){
auto it1=lower_bound(pos[i].begin(), pos[i].end(), l);
auto it2=upper_bound(pos[i].begin(), pos[i].end(), r);
ans+=1LL*(it2-it1)*(it2-it1-1)/2;
}
cout<<ans<<endl;
}
复杂度分析
前缀和 处理,
查询,
二分法
查找

京公网安备 11010502036488号