【HDU】5213 Lucky 【分块(在线算法)】

传送门:【HDU】5213 Lucky

题目分析:

我来说一下这题的在线做法。

首先我们将区间分成 n 块,用f[x][y]表示第x块的数和第y块的数相加等于K的对数,这个可以 O(nn) 的预处理。然后还有g[x][y]表示在第1~x块中有的大小为y的数的个数,这个的复杂度同样 O(nn)

接下来,对于每组询问,我们考虑一个区间,这个区间内完整的块最多 n 个,且除了完整的块以后,也只有 n 个分散的数。

A =第一个区间内完整的块, B =第一个区间内分散的数, C =第二个区间内完整的块, D =第二个区间内分散的数。

XY 表示 X Y 的共同作用对答案的贡献,则本次询问的答案ans= AC+AD+BC+BD

这样我们就做到了在线处理了。

my code:



#include <stdio.h> #include <string.h> #include <set> #include <map> #include <math.h> #include <algorithm> using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) #define cpy( a , x ) memcpy ( a , x , sizeof a ) const int MAXN = 30005 ; const int SQR = 300 ; int n , m , K , sqr ; int a[MAXN] ; int f[SQR][SQR] ; int g[SQR][MAXN] ; int vis[MAXN] , Time ; int cnt[MAXN] , cnt2[MAXN] ; void solve () { int l1 , l2 , r1 , r2 ; clr ( f , 0 ) ; clr ( a , 0 ) ; clr ( g , 0 ) ; sqr = sqrt ( 1.0 * n ) ; for ( int i = 1 ; i <= n ; ++ i ) scanf ( "%d" , &a[i] ) ; for ( int i = 1 , x = 1 ; i <= n ; i += sqr , ++ x ) { for ( int j = i ; j <= min ( i + sqr - 1 , n ) ; ++ j ) ++ g[x][a[j]] ; for ( int j = 1 ; j <= n ; ++ j ) g[x][j] += g[x - 1][j] ; for ( int j = 1 , y = 1 ; j <= n ; j += sqr , ++ y ) { ++ Time ; for ( int k = j ; k <= min ( j + sqr - 1 , n ) ; ++ k ) { if ( vis[a[k]] == Time ) ++ cnt[a[k]] ; else { vis[a[k]] = Time ; cnt[a[k]] = 1 ; } } for ( int k = i ; k <= min ( i + sqr - 1 , n ) ; ++ k ) { if ( K - a[k] > 0 && K - a[k] <= n && vis[K - a[k]] == Time ) { f[x][y] += cnt[K - a[k]] ; } } } for ( int y = 1 ; y < SQR ; ++ y ) f[x][y] += f[x][y - 1] ; } scanf ( "%d" , &m ) ; for ( int o = 1 ; o <= m ; ++ o ) { scanf ( "%d%d%d%d" , &l1 , &r1 , &l2 , &r2 ) ; int ans = 0 ; int L1 = ( l1 - 1 ) / sqr + 2 ; int R1 = ( r1 - 1 ) / sqr ; int L2 = ( l2 - 1 ) / sqr + 2 ; int R2 = ( r2 - 1 ) / sqr ; if ( L1 <= R1 && L2 <= R2 ) { for ( int i = L1 ; i <= R1 ; ++ i ) { ans += f[i][R2] - f[i][L2 - 1] ; } } ++ Time ; int t = min ( r2 , ( L2 - 1 ) * sqr ) ; for ( int i = l2 ; i <= t ; ++ i ) { int tt = K - a[i] ; if ( tt > 0 && tt <= n & R1 >= L1 ) ans += g[R1][tt] - g[L1 - 1][tt] ; if ( vis[a[i]] == Time ) ++ cnt2[a[i]] ; else { vis[a[i]] = Time ; cnt2[a[i]] = 1 ; } } if ( t != r2 ) { for ( int i = R2 * sqr + 1 ; i <= r2 ; ++ i ) { int tt = K - a[i] ; if ( tt > 0 && tt <= n && R1 >= L1 ) ans += g[R1][tt] - g[L1 - 1][tt] ; if ( vis[a[i]] == Time ) ++ cnt2[a[i]] ; else { vis[a[i]] = Time ; cnt2[a[i]] = 1 ; } } } t = min ( r1 , ( L1 - 1 ) * sqr ) ; for ( int i = l1 ; i <= t ; ++ i ) { int tt = K - a[i] ; if ( tt > 0 && tt <= n && R2 >= L2 ) ans += g[R2][tt] - g[L2 - 1][tt] ; if ( tt > 0 && tt <= n && vis[tt] == Time ) ans += cnt2[tt] ; } if ( t != r1 ) { for ( int i = R1 * sqr + 1 ; i <= r1 ; ++ i ) { int tt = K - a[i] ; if ( tt > 0 && tt <= n && R2 >= L2 ) ans += g[R2][tt] - g[L2 - 1][tt] ; if ( tt > 0 && tt <= n && vis[tt] == Time ) ans += cnt2[tt] ; } } printf ( "%d\n" , ans ) ; } } int main () { Time = 0 ; clr ( vis , 0 ) ; while ( ~scanf ( "%d%d" , &n , &K ) ) solve () ; return 0 ; } 

你可能感兴趣的:(预处理,分块)