测试地址:Time to Raid Cowavans
题目大意:维护一个长为
n(≤3×105)
n
(
≤
3
×
10
5
)
的数列
A
A
,要求处理个询问,每次询问给出一个数对
(a,b)
(
a
,
b
)
,询问
Aa+Aa+b+Aa+2b+...+Aa+kb
A
a
+
A
a
+
b
+
A
a
+
2
b
+
.
.
.
+
A
a
+
k
b
的值,其中
a+kb≤n
a
+
k
b
≤
n
但
a+(k+1)b>n
a
+
(
k
+
1
)
b
>
n
。
做法:本题需要用到分块+离线处理。
直接
O(nm)
O
(
n
m
)
的暴力肯定是会炸的,需要考虑优化。
我们发现对于
b≥n−−√
b
≥
n
的询问,每次暴力求值的复杂度不超过
O(n−−√)
O
(
n
)
,总复杂度为
O(mn−−√)
O
(
m
n
)
,可以接受。
重点是处理
b<n−−√
b
<
n
的询问,我们可以对于每个不同的
b
b
值,对所有我们
O(n)
O
(
n
)
处理出题目要求的后缀和,这样就可以
O(1)
O
(
1
)
回答询问了。对于每个
b
b
值都是的复杂度,而
b
b
值共有种,所以总复杂度为
O(nn−−√)
O
(
n
n
)
。
但是
O(nn−−√)
O
(
n
n
)
的空间复杂度对于70MB的空间限制来说太大了,注意到题目没有强制在线,所以我们在一开始将所有询问对
b
b
排序,然后顺次处理下来,这样空间复杂度就降为,可以接受。这样我们就以
O((n+m)n−−√)
O
(
(
n
+
m
)
n
)
的复杂度解决了这一问题。
(实际上我不太清楚这个题到底是不是真正的分块思想,如果标错了请见谅)
以下是本人代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n,sq,m;
ll a[300010],ans[300010],sum[300010];
struct Query
{
int id,a,b;
}q[300010];
bool cmp(Query a,Query b)
{
return a.b<b.b;
}
int main()
{
scanf("%d",&n);
sq=(int)sqrt(n);
for(int i=1;i<=n;i++)
scanf("%I64d",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
q[i].id=i;
scanf("%d%d",&q[i].a,&q[i].b);
}
q[0].b=0;
sort(q+1,q+m+1,cmp);
for(int i=1;i<=m;i++)
{
if (q[i].b<sq)
{
if (q[i].b!=q[i-1].b)
{
for(int j=n;j>=1;j--)
{
if (j>n-q[i].b) sum[j]=a[j];
else sum[j]=sum[j+q[i].b]+a[j];
}
}
ans[q[i].id]=sum[q[i].a];
}
else
{
ans[q[i].id]=0;
for(int j=q[i].a;j<=n;j+=q[i].b)
ans[q[i].id]+=a[j];
}
}
for(int i=1;i<=m;i++)
printf("%I64d\n",ans[i]);
return 0;
}