JZOJ4744. 同余

题目大意

给定一个长度为 n 的序列ai m 个询问。
每个询问(l,r,p,q),表示询问在 [l,r] 之间有多少个 ai 满足 ai%p=q

Data Constraint
n,m100000,ai10000

题解

先考虑求区间 [1,r] 的答案。
ai=kp+q
p 很大时,k的取值很少。
所以维护 h[i] 表示 i 有多少个,g[i][j]表示对 i 取模为j的有多少个。
p 很大时在h中查询,否则在 g <script type="math/tex" id="MathJax-Element-968">g</script>中查询。

SRC

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

#define K 100000 + 10
#define N 10000 + 10
#define M 100 + 10
struct Query {
    int h ;
    int l , r , p , q ;
} Q[K] ;

int h[N] , g[M][M] ;
int a[K] , ans[K] ;
int n , m ;

bool cmpr( Query a , Query b ) { return a.r < b.r || ( a.r == b.r && a.l < b.l ) ; }
bool cmpl( Query a , Query b ) { return a.l < b.l || ( a.l == b.l && a.r < b.r ) ; }

int main() {
    scanf( "%d%d" , &n , &m ) ;
    for (int i = 1 ; i <= n ; i ++ ) scanf( "%d" , &a[i] ) ;
    for (int i = 1 ; i <= m ; i ++ ) scanf( "%d%d%d%d" , &Q[i].l , &Q[i].r , &Q[i].p , &Q[i].q ) , Q[i].h = i ;
    sort( Q + 1 , Q + m + 1 , cmpr ) ;
    int top = 1 ;
    for (int i = 1 ; i <= n && top <= m ; i ++ ) {
        h[a[i]] ++ ;
        for (int k = 1 ; k <= 100 ; k ++ ) g[k][a[i]%k] ++ ;
        while ( top <= m && Q[top].r == i ) {
            if ( Q[top].p <= 100 ) ans[Q[top].h] += g[Q[top].p][Q[top].q] ;
            else {
                for (int k = 0 ; Q[top].p * k + Q[top].q <= 10000 ; k ++ ) ans[Q[top].h] += h[Q[top].p * k + Q[top].q] ;
            }
            top ++ ;
        }
    }
    top = 1 ;
    memset( h , 0 , sizeof(h) ) ;
    memset( g , 0 , sizeof(g) ) ;
    sort( Q + 1 , Q + m + 1 , cmpl ) ;
    for (int i = 1 ; i <= n && top <= m ; i ++ ) {
        while ( top <= m && Q[top].l == i ) {
            if ( Q[top].p <= 100 ) ans[Q[top].h] -= g[Q[top].p][Q[top].q] ;
            else {
                for (int k = 0 ; Q[top].p * k + Q[top].q <= 10000 ; k ++ ) ans[Q[top].h] -= h[Q[top].p * k + Q[top].q] ;
            }
            top ++ ;
        }
        h[a[i]] ++ ;
        for (int k = 1 ; k <= 100 ; k ++ ) g[k][a[i]%k] ++ ;
    }
    for (int i = 1 ; i <= m ; i ++ ) printf( "%d\n" , ans[i] ) ;
    return 0 ;
}

以上.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值