zoukankan      html  css  js  c++  java
  • 【bzoj2506】calc 根号分治+STL-vector+二分+莫队算法

    题目描述

    给一个长度为n的非负整数序列A1,A2,…,An。现有m个询问,每次询问给出l,r,p,k,问满足l<=i<=r且Ai mod p = k的值i的个数。

    输入

    第一行两个正整数n和m。
    第二行n个数,表示A1,A2,…,An。
    以下m行,每行四个数分别表示l,r,p,k。满足1<=l<=r<=n。

    输出

    对于每个询问,输出一行,表示可行值i的个数。

    样例输入

    5 2
    1 5 2 3 7
    1 3 2 1
    2 5 3 0

    样例输出

    2
    1


    题解

    根号分治+STL-vector+二分+莫队算法

    对于$ple sqrt A$的部分,由于只有$sqrt A$种模数,因此我们可以开$vector[i][j]$维护模$i$等于$j$的数的出现位置,查询时直接在$vector[p][k]$上二分即可。这个过程预处理时间是$O(nsqrt A)$,单次查询时间是$O(log n)$。

    对于$p>sqrt A$的部分,考虑到满足$mod p=k$的数最多只有$sqrt A$个,因此可以暴力统计这些数中的每一个在序列中的出现次数。由于此时再使用vector+二分的话时间复杂度为$O(nsqrt Alog n)$,会TLE,因此需要使用莫队算法并使用桶来维护每个数的出现次数。这样极限复杂度为$O(nsqrt n+nsqrt A)$。

    因此总的最坏时间复杂度为$O(nsqrt n+nsqrt A)$。

    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    vector<int> v[210][210];
    int a[100010] , cnt[10010] , ans[100010] , si , tot;
    struct data
    {
    	int l , r , p , k , id;
    	bool operator<(const data &a)const {return (l - 1) / si == (a.l - 1) / si ? r < a.r : l < a.l;}
    }q[100010];
    int main()
    {
    	int n , m , i , j , w , x , y , z , lp = 1 , rp = 0;
    	scanf("%d%d" , &n , &m) , si = (int)sqrt(n);
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		scanf("%d" , &a[i]);
    		for(j = 1 ; j <= 100 ; j ++ )
    			v[j][a[i] % j].push_back(i);
    	}
    	for(i = 1 ; i <= m ; i ++ )
    	{
    		scanf("%d%d%d%d" , &w , &x , &y , &z);
    		if(y <= 100) ans[i] = upper_bound(v[y][z].begin() , v[y][z].end() , x) - lower_bound(v[y][z].begin() , v[y][z].end() , w);
    		else q[++tot].l = w , q[tot].r = x , q[tot].p = y , q[tot].k = z , q[tot].id = i;
    	}
    	sort(q + 1 , q + tot + 1);
    	for(i = 1 ; i <= tot ; i ++ )
    	{
    		while(lp > q[i].l) lp -- , cnt[a[lp]] ++ ;
    		while(rp < q[i].r) rp ++ , cnt[a[rp]] ++ ;
    		while(lp < q[i].l) cnt[a[lp]] -- , lp ++ ;
    		while(rp > q[i].r) cnt[a[rp]] -- , rp -- ;
    		for(j = q[i].k ; j <= 10000 ; j += q[i].p) ans[q[i].id] += cnt[j];
    	}
    	for(i = 1 ; i <= m ; i ++ ) printf("%d
    " , ans[i]);
    	return 0;
    }
    

     

  • 相关阅读:
    [转]Linux(Ubuntu)下如何安装JDK
    第一个MICO CORBA demo实录
    解决/usr/bin/ld: cannot find -lssl
    使用adb shell 进入手机修改文件的权限
    解决某些Android Permission denied
    Java 8新特性终极指南
    Win10系统出问题?简单一招即可修复win10!
    运行时数据区
    linux下vi命令大全
    关于java中final关键字与线程安全性
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7570795.html
Copyright © 2011-2022 走看看