Hackerrank Week of Code 30 Range Modular Queries

5 篇文章 0 订阅
2 篇文章 0 订阅

题目大意

给定一个长度为 n 的序列,有q个询问,每个询问要求 [l,r] 之间有多少个 ai % x=y

Data Constraint
n,q,ai4×104

题解

当询问的 x 小于等于n的时候,显然可以分块预处理。
x 大于n的时候, x 的倍数小于n个,所以可以莫队,记录一个桶。

时间复杂度: O(nn)

SRC

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std ;

#define N 40000 + 10
#define M 200 + 10
struct Query {
    int l , r , x , y ;
    int h ;
} Q[N] ;

int Num[M][M][M] , T[N] ;
int a[N] , Belong[N] , Ans[N] ;
int n , m , Cnt , Block , Maxv ;

bool cmp( Query a , Query b ) { return Belong[a.l] < Belong[b.l] || ( Belong[a.l] == Belong[b.l] && a.r < b.r ) ; }

void Modify( int l , int r , int del ) {
    for (int i = l ; i <= r ; i ++ ) T[a[i]] += del ;
}

int main() {
    scanf( "%d%d" , &n , &m ) ;
    Block = 200 ;
    for (int i = 1 ; i <= n ; i ++ ) {
        scanf( "%d" , &a[i] ) ;
        Maxv = max( Maxv , a[i] ) ;
        Belong[i] = i / Block + ( i % Block != 0 ) ;
    }
    for (int i = 1 ; i <= Block ; i ++ ) {
        int now = 1 ;
        for (int j = 1 ; j <= n ; j ++ ) {
            if ( Belong[j] != now ) {
                now ++ ;
                for (int k = 0 ; k < i ; k ++ ) Num[i][now][k] = Num[i][now-1][k] ;
            }
            Num[i][now][a[j]%i] ++ ;
        }
    }
    for (int i = 1 ; i <= m ; i ++ ) {
        int l , r , x , y ;
        scanf( "%d%d%d%d" , &l , &r , &x , &y ) ;
        l ++ , r ++ ;
        if ( x <= Block ) {
            int fl = Belong[l] ;
            int fr = Belong[r] ;
            if ( fl < fr ) Ans[i] = Num[x][fr-1][y] - Num[x][fl][y] ;
            if ( fl != fr ) {
                for (int j = l ; j <= min( fl * Block , n ) ; j ++ )
                    if ( a[j] % x == y ) Ans[i] ++ ;
                for (int j = (fr - 1) * Block + 1 ; j <= r ; j ++ )
                    if ( a[j] % x == y ) Ans[i] ++ ;
            } else {
                for (int j = l ; j <= r ; j ++ )
                    if ( a[j] % x == y ) Ans[i] ++ ;
            }
        } else {
            ++ Cnt ;
            Q[Cnt].l = l , Q[Cnt].r = r , Q[Cnt].x = x , Q[Cnt].y = y ;
            Q[Cnt].h = i ;
        }
    }
    sort( Q + 1 , Q + Cnt + 1 , cmp ) ;
    int lasl = 1 , lasr = 0 ;
    for (int i = 1 ; i <= Cnt ; i ++ ) {
        if ( lasl < Q[i].l ) Modify( lasl , Q[i].l - 1 , -1 ) ;
        if ( lasr > Q[i].r ) Modify( Q[i].r + 1 , lasr , -1 ) ;
        if ( lasl > Q[i].l ) Modify( Q[i].l , lasl - 1 , 1 ) ;
        if ( lasr < Q[i].r ) Modify( lasr + 1 , Q[i].r , 1 ) ;
        for (int k = Q[i].y ; k <= Maxv ; k += Q[i].x )
            Ans[Q[i].h] += T[k] ;
        lasl = Q[i].l , lasr = Q[i].r ;
    }
    for (int i = 1 ; i <= m ; i ++ ) printf( "%d\n" , Ans[i] ) ;
    return 0 ;
}

以上.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值