题意:
给定长度为n的序列a,
q次询问,每次询问给出t和k,要求计算
a
t
+
a
t
+
k
+
.
.
.
a
t
+
p
k
a_{t}+a_{t+k}+...a_{t+pk}
at+at+k+...at+pk,其中t+(p+1)k>n
数据范围:n,q<=3e5,a(i)<=1e9
解法:
分块。
令sq=sqrt(n),
1.k>=sq时暴力,复杂度是O(sq)的。
2.k<sq时,可以先O(n*sq)预处理temp[t][k],对于询问O(1)处理。
但是这题n*sq的空间开不下,解决方法是将k<sq的询问离线存储,将询问按照k排序,
对于当前的k’,O(n)预处理temp[],temp[i]表示
a
i
+
a
i
+
k
+
.
.
.
a
i
+
p
k
a_{i}+a_{i+k}+...a_{i+pk}
ai+ai+k+...ai+pk,然后就可以O(1)处理询问了。
当遇到与之前不同的k的时,重新O(n)预处理temp[],
因为k只有sq种取值,因此k次预处理的总复杂度最多也只有O(n sq)
code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxm=3e5+5;
struct QQ{
int t,k,id;
}Q[maxm];
ll temp[maxm];
ll ans[maxm];
int a[maxm];
int n,q;
bool cmp(QQ a,QQ b){
return a.k<b.k;
}
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
//
scanf("%d",&q);
int sq=sqrt(n);
int cnt=0;
for(int i=1;i<=q;i++){
int t,k;scanf("%d%d",&t,&k);
if(k>=sq){//暴力,O(sq)
for(int j=t;j<=n;j+=k){
ans[i]+=a[j];
}
}else{//<sq的k只有sq种
Q[++cnt]={t,k,i};
}
}
sort(Q+1,Q+1+cnt,cmp);
for(int i=1;i<=cnt;i++){
int t=Q[i].t,k=Q[i].k;
if(k!=Q[i-1].k){//k不同,重新预处理,(k<sq种,因此最多更新sq次,sq次总共O(n*sq))
for(int j=n;j>=1;j--){
temp[j]=a[j];
if(j+k<=n)temp[j]+=temp[j+k];
}
}
ans[Q[i].id]=temp[t];
}
for(int i=1;i<=q;i++){
printf("%lld\n",ans[i]);
}
return 0;
}