題解 洛谷 P3396 【哈希衝突】(根號分治)

根號分治

前言

本題是一道講解根號分治思想的論文題(然鵝我並無找到論文),正ios

如論文中所說,根號算法——不只是分塊,根號分治利用的思想和分塊像c++

似卻又不一樣,某一篇洛穀日報中說過,分塊算法實質上是一種是經過分紅算法

多塊後在每塊上打標記以實現快速區間修改,區間查詢的一種算法。根號優化

分治與其思路類似,將本來若一次性解決時間複雜度很高的問題分塊去解spa

決來下降總體的時間複雜度。code

例題

以本題舉例子哈希衝突ci

本題做爲論文的第一道題目,是一道很好的練習題,注意,本體給出的get

\(value[i]\)\(i\) 在序列中出現的次數,不要把題讀錯了(一開始我就讀錯了)string

咱們首先閱讀題目,發現,不管是 \(O(n^2)\) 預處理, \(O(1)\) 查詢,仍是在io

查詢時直接\(O(n^2)\)獲取答案,都是 \(O(n^2)\) 的時間複雜度,咱們考慮對

其進行優化,咱們能夠考慮將\(p\),也就是模數按根號分塊處理

對於 \(p<=\sqrt{q}\) 咱們直接 \(O(n\sqrt{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(n\sqrt{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;
}

到這裏本題解就結束了

完結撒花!!

相關文章
相關標籤/搜索