题目
题目链接:https://codeforces.com/problemset/problem/103/D
给一个序列
a
a
a ,
m
m
m 次询问,每次询问给出
t
,
k
t, k
t,k 。求
a
t
+
a
t
+
k
+
a
t
+
2
k
+
⋯
+
a
t
+
p
k
a_t + a_{t+k}+a_{t+2k}+\cdots+a_{t+pk}
at+at+k+at+2k+⋯+at+pk 其中
t
+
p
k
≤
n
t+pk \leq n
t+pk≤n 且
t
+
(
p
+
1
)
k
>
n
t+(p+1)k > n
t+(p+1)k>n。
n
,
m
≤
300000
,
a
i
≤
1
0
9
n,m \leq 300000,a_i \leq 10^9
n,m≤300000,ai≤109。
思路
一眼题吧。
考虑一个阈值
t
t
t,对于
k
≤
t
k\leq t
k≤t 的询问,
O
(
t
n
)
O(tn)
O(tn) 预处理出来然后
O
(
1
)
O(1)
O(1) 回答,对于
k
>
t
k>t
k>t 的询问,直接
O
(
n
t
)
O(\frac{n}{t})
O(tn) 回答。
取
t
=
n
≈
350
t=\sqrt{n}\approx 350
t=n≈350,时间复杂度为
O
(
m
n
)
O(m\sqrt{n})
O(mn)。把询问离线一下就可以做到空间复杂度
O
(
n
)
O(n)
O(n)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=301000,M=550;
int n,m,a[N];
ll sum[N],ans[N];
struct node
{
int x,y,id;
}b[N];
bool cmp(node x,node y)
{
return x.y<y.y;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&b[i].x,&b[i].y);
b[i].id=i;
}
sort(b+1,b+1+m,cmp);
for (int i=1;i<=m;i++)
if (b[i].y<=M)
{
if (b[i].y!=b[i-1].y)
for (int j=n;j>=1;j--)
sum[j]=sum[j+b[i].y]+a[j];
ans[b[i].id]=sum[b[i].x];
}
else
{
for (int j=b[i].x;j<=n;j+=b[i].y)
ans[b[i].id]+=a[j];
}
for (int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}