zoukankan      html  css  js  c++  java
  • 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治

    前言

    本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正

    如论文中所说,根号算法——不仅是分块,根号分治利用的思想和分块像

    似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种是通过分成

    多块后在每块上打标记以实现快速区间修改,区间查询的一种算法。根号

    分治与其思路相似,将原本若一次性解决时间复杂度很高的问题分块去解

    决来降低整体的时间复杂度。

    例题

    以本题举例子哈希冲突

    本题作为论文的第一道题目,是一道很好的练习题,注意,本体给出的

    (value[i])(i) 在序列中出现的次数,不要把题读错了(一开始我就读错了)

    我们首先阅读题目,发现,无论是 (O(n^2)) 预处理, (O(1)) 查询,还是在

    查询时直接(O(n^2))获取答案,都是 (O(n^2)) 的时间复杂度,我们考虑对

    其进行优化,我们可以考虑将(p),也就是模数按根号分块处理

    对于 (p<=sqrt{q}) 我们直接 (O(nsqrt{n})) 进行预处理,

    	for(int i=1;i<=n;i++){
    		v=read();
    		val[i]=v;
    	}
    	size=sqrt(n); 
    	for(int i=1;i<=n;i++){
    		for(int p=1;p<=size;p++){
    			ans[p][i%p]+=val[i]; 
    		}
    	}
    

    (ans[p][i]) 表示在 (%p) 后值为 (i)的数的个数

    (p>sqrt{q}) 的情况,

    我们直接暴力得出答案,暴力得到答案的时间复杂度为 (O(sqrt{n}))

    	int an=val[y]; 
    	for(int i=x+y;i<=n;i+=x){
    		an+=val[i]; 
    	}
    	cout<<an<<endl;
    

    (an=val[y]) 是为了处理 (y%x=y) ((y<x)) 的情况,为什么说我们暴力跳

    答案时间复杂度是 (O(sqrt{n})) 呢?我们当前的 (p>sqrt{n})) 因为统

    计答案时每一次要跳(p)个数,所以有贡献的数一定小于 (frac{n} {p}) 也就是 (sqrt{n}) ,所以暴力得到答案的时间复杂度为 (O(sqrt{n}))

    每一次修改,我们只需要修改 (p<=sqrt{n}) 的情况即可,时间复杂度也是 (O(sqrt{n}))

    	cin>>x>>y;
    	int l=y-val[x];
    	val[x]=y; 
    	for(int p=1;p<=size;p++){
    		ans[p][x%p]+=l;
    	}
    

    所以在本题,我们运用根号分治的想法,把时间复杂度由原本的(O(n^2))

    优化到了 (O(nsqrt{n})) 从而解决本题。

    莫名觉得根号分治挺像折半搜索
    ,推荐一道练习题CF444D DZY Loves Strings
    还是很有难度的

    代码

    放一下全部代码吧

    #include<iostream>
    #include<string>
    #include<string>
    #include<cstdio>
    #include<cmath>
    #define int long long
    using namespace std;
    const int maxn=3e5+10;
    inline int read(){
    	int ret=0;
    	int f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){
    		if(ch=='-')	
    			f=-f;
    		ch=getchar();
    	}
    	while(ch<='9'&&ch>='0'){
    		ret=ret*10+(ch^'0');
    		ch=getchar();
    	}
    	return ret*f;
    }
    int val[maxn];
    int n,m;
    int p;
    int ans[2000][2000];
    int size;
    char a;
    signed main(){
    //	freopen("a.in","r",stdin);
    	n=read();
    	m=read();
    	int v;
    	for(int i=1;i<=n;i++){
    		v=read();
    		val[i]=v;//???????? 
    	}
    	size=sqrt(n);//???? 
    	for(int i=1;i<=n;i++){
    		for(int p=1;p<=size;p++){
    			ans[p][i%p]+=val[i]; 
    		}
    	}
    	int x,y;
    	while(m--){
    		cin>>a;
    		if(a=='A'){
    			x=read();
    			y=read();
    			if(x<=size){
    				cout<<ans[x][y]<<endl;
    			}
    			else{
    				int an=val[y]; 
    				for(int i=x+y;i<=n;i+=x){
    						an+=val[i]; 
    				}
    				cout<<an<<endl;
    			} 
    		}
    		if(a=='C'){
    			cin>>x>>y;
    			int l=y-val[x];
    			val[x]=y; 
    			for(int p=1;p<=size;p++){
    				ans[p][x%p]+=l;
    			}
    		}
    	}
    	return 0;
    }
    

    到这里本题解就结束了

    完结撒花!!

  • 相关阅读:
    Error 1031
    电信短信转移取消
    手机模拟手柄操作电脑游戏
    MySQL 5.7 InnoDB Cluster 部署
    Bitwarden_rs搭建
    脚本:Tomcat日志切割
    报错:The server cannot be started because one or more of the ports are invalid. Open the server editor and correct the invalid ports.
    Linux启动过程详解
    UNIX环境高级编程__针对apue.h找不到的情况以及log错误信息输出的问题
    C++primer_拷贝控制之13.26联系控制成员实现类值行为
  • 原文地址:https://www.cnblogs.com/rpup/p/14077621.html
Copyright © 2011-2022 走看看