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