Codeforces103 D. Time to Raid Cowavans(分块,离线)

题意:

给定长度为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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值