Time to Raid Cowavans ( 非分块sqrt(n)算法 + 离线查询特性应用

题意:给定数组c[n],及多组a,b ,求每一组的后缀和 c[a]+c[a+b]+c[a+2*b]+c[a+3*b].......

 

分析:

 对于每一个b值 ,都可以在o(n)的复杂度内利用dp 求出该b下不同a值对应的后缀和sum[a]:

 

                 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];
                 }

dp一次后,对于不同a值的询问都是o(1)复杂度的;

我们也可以暴力在o(n/b)的复杂度内对一组a,b求解:

             while( q[i].a <=n){
                 ans[ q[i].id ]+=a[ q[i].a ];
                 q[i].a+=q[i].b;
             }

 

以sqrt(n)分界,b大于sqrt(n)暴力复杂度为o(sqrt(n)),可以接受;

b小于sqrt(n)直接dp,最多有sqrt(n)个不同b值,复杂度为o( n*sqrt(n) ),可以接受;

 

由于没有在线查询,即输入一组数据立即给出答案,我们可以对每一组(a,b)按b排序,b相同的一起处理,相同的b只用一次dp就够了,然后把每一次的结果存在ans[i]中,按查询顺序输出即可

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int sq , n ,m;

ll  a[300000+500];
ll  ans[300000+500] ,sum[300000+500];

struct Query{
     int id, a ,b;
} q[300000+500];

bool cmp( const Query & a ,const Query & b){
      return a.b < b.b;
}
int main( ){
     scanf("%d" ,&n);
     sq = 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+1+m ,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;
             while( q[i].a <=n){
                 ans[ q[i].id ]+=a[ q[i].a ];
                 q[i].a+=q[i].b;
             }
         }
     }

     for( int i=1 ;i<=m ;i++)
        printf("%I64d\n" ,ans[i]);
     return 0;
}
posted @ 2019-04-20 11:01  易如鱼  阅读(281)  评论(0编辑  收藏  举报