【CF103D】Time to Raid Cowavans-分块+离线处理

测试地址:Time to Raid Cowavans
题目大意:维护一个长为n(3×105)的数列A,要求处理m(3×105)个询问,每次询问给出一个数对(a,b),询问Aa+Aa+b+Aa+2b+...+Aa+kb的值,其中a+kbna+(k+1)b>n
做法:本题需要用到分块+离线处理。
直接O(nm)的暴力肯定是会炸的,需要考虑优化。
我们发现对于bn的询问,每次暴力求值的复杂度不超过O(n),总复杂度为O(mn),可以接受。
重点是处理b<n的询问,我们可以对于每个不同的b值,对所有a我们O(n)处理出题目要求的后缀和,这样就可以O(1)回答询问了。对于每个b值都是O(n)的复杂度,而b值共有n种,所以总复杂度为O(nn)
但是O(nn)的空间复杂度对于70MB的空间限制来说太大了,注意到题目没有强制在线,所以我们在一开始将所有询问对b排序,然后顺次处理下来,这样空间复杂度就降为O(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
",ans[i]);

    return 0;
}
原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793534.html