好题集 (7) - LG P9809 [SHOI2006] 作业 Homework

题目传送门

题意:维护一个集合 \(S\),有 \(n\) 此操作,操作分为修改和查询。修改时将给定的 \(x\) 插入 \(S\) 中,查询时对于给定的 \(y\),求 \(\forall x\in S,\min (x\bmod y)\)\(n\le 10^5\)\(x,y\le 3\times 10^5\)

看到诡异取模,联想到对 \(y\) 根号分治。设阈值为 \(B\),分 \(y\le B\)\(y>B\) 两种情况讨论。

首先对于 \(\forall i\in[1,B]\),都维护一个 \(val_i\) 表示已有的 \(x\) 中,\(\min (x\bmod i)\)。对于 \(y\le B\) 的查询操作,直接将 \(val_y\) 作为答案即可,这一步是 \(O(1)\) 的;每插入一个新的 \(x\),都对应更新 \(val_i\),这一步是 \(O(B)\) 的。

考虑对于 \(y>B\) 的查询应该怎么做。我们把对每个 \(x\) 取模的式子列出来:

\[x\equiv r\pmod y \]

其中 \(r\) 是余数,\(\min r\) 即为答案。

\(a\) 为商,再把式子变一下形:

\[x=ay+r \]

观察发现,\(y>B\) 就意味着 \(a<\frac{x}{B}\)。这是一个很重要的性质,我们可以利用这个性质来枚举 \(a\),并将每个 \(a\) 对应的 \(r\) 取最小值作为答案。枚举的过程是 \(O(\frac{x}{B})\) 的。

考虑我们当前枚举到了一个 \(a\),如何求出对应的 \(r\)。显然这时 \(x\)\(ay\) 的后继(可以取等)是最优的。如果这样的 \(x\) 存在,那么这个 \(a\) 对应的答案就是 \(x\bmod y\)

于是对于一次 \(y>B\) 的查询,我们一共要求 \(O(\frac{V}{B})\) 次后继;而对于一次修改,我们只需插入一次。显然常规值域分块的 \(O(1)\) 插入,\(O(\sqrt{n})\) 求后继是不够看的;平衡树等二分数据结构也不是优。于是不难想到改变值域分块的维护方式,牺牲一部分插入的复杂度来平衡求后继的复杂度,做到 \(O(\sqrt{n})\) 插入,\(O(1)\) 求后继。

容易想到维护每个数在块内的后继(若无则设为 $\infty $)和每块右端点上的数在后面所有块中的后继。更新时容易以 \(O(\sqrt{n})\) 的复杂度维护,查询时直接将两个值取最小即可,做到 \(O(1)\)

发现 \(B\)\(\sqrt{V}\) 时比较优,此时总复杂度为 \(O(n\sqrt{V})\)

代码(题中的 \(y\) 在代码中叫 \(x\)):

#include<iostream>
#include<cmath>
#include<queue>
using namespace std;

const int N=3e6+5;
const int B=550;

int n;
int val[N];

namespace OIfast{
	
	char buf[1<<21],*p1,*p2,*top,buffer[1<<21];
	#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?0:*p1++)
	#define gc getchar()
	
	inline int read(){
		int n=0;static char c=gc;
		while(!isdigit(c))c=gc;
		while(isdigit(c))n=(n<<3)+(n<<1)+(c^48),c=gc;
		return n;
	}
	
}using namespace OIfast;

namespace FK{
	
	const int M=1e4+5;
	
	int k,tot;
	
	int L[M],R[M],loc[N];
	int nxt[N],nxt_[M];
	
	inline void getmn(int &a,int b){
		return a=(a<b?a:b),void();
	}
	
	inline void init(){
		k=550,tot=ceil((3e5)/(1.0*k));
		for(int i=1;i<=tot;++i){
			L[i]=(i-1)*k,R[i]=min((int)3e5,L[i]+k-1);
			nxt_[i]=1e9;
			for(int j=L[i];j<=R[i];++j)loc[j]=i,nxt[j]=1e9;
		}
		for(int i=1;i<=B;++i)val[i]=1e9;
		return ;
	}
	
	inline void add(int v){
		for(int i=L[loc[v]];i<=v;++i)getmn(nxt[i],v);
		for(int i=1;i<=loc[v]-1;++i)getmn(nxt_[i],v);
		return ;
	}
	
	inline int qry(int v){
		return min(nxt_[loc[v]],nxt[v]);
	}
	
}using namespace FK;

inline void work(){
	char op=gc;while(!isalpha(op))op=gc;
	int x=read();
	if(1==2){
		puts("wow");
	}else if(op=='A'){
		for(int i=1;i<=B;++i)getmn(val[i],x%i);
		add(x);
	}else if(op=='B'){
		if(x<=B)printf("%d\n",val[x]);
		else{
			int res=1e9;
			for(int i=0;i*x<=3e5;++i)if(qry(i*x)<1e9)getmn(res,qry(i*x)%x);
			printf("%d\n",res);
		}
	}
	return ;
}

signed main(){
//	freopen("P9809_1.in","r",stdin),freopen("out.txt","w",stdout);
	n=read();init();while(n--)work();
	return 0;
}

提交记录

posted @ 2025-12-21 15:17  DX3906_ourstar  阅读(4)  评论(0)    收藏  举报