CWOI DS 专题

发布时间 2023-09-22 08:57:50作者: xx019

O - 你的名字。

哎,卡常。

考虑根号分治。当 \(k\le T\) 时我们对每种可能的 \(k\) 预处理 \(a_i\bmod k\),然后分成 \(\sqrt{n}\) 块,每块块内维护前后缀最小值,对所有块再跑 ST 表。当询问两端点在同一块内时暴力查询,不在同一块内时分成整块和散块 \(\mathcal{O}(1)\) 查询,复杂度 \(\mathcal{O}(T(n+\sqrt{n}\log\sqrt{n})+\sum[k_i\le T])\);当 \(k>T\) 时发现 \(\dfrac{V}{k}\) 不会太大,可以枚举 \(i\),每次只考虑 \(a_j\in[ik,(i+1)k)\) 的位置,然后类似上述做法处理。

发现此时空间复杂度是 \(\mathcal{O}(\dfrac{mV}{T})\) 级别的,不太能行。不妨转为枚举 \(ik\),此时不需要额外开空间。同时由于本题求最小值,我们只用保证 \(a_j\ge ik\) 即可,于是可以从大到小枚举,每次逐渐加入,单次修改复杂度为 \(\mathcal{O}(\sqrt{n}+(1+2+4+\ldots \sqrt{n}))=\mathcal{O}(\sqrt{n})\) 级别,总复杂度 \(\mathcal{O}(n\sqrt{n}+V\ln V+\sum[k_i>T])\)

注意本题非常卡常,有几个细节需要注意:

  • 适当调整块长,经试验取在 630 左右最优;

  • 快读,以及其他所有常用、基本的卡常技巧,以及不要用 vector;

  • 玄学的估价函数:可以大概预估一下两种方法需要的大概时间,然后考虑选哪种;

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
struct IO {
#define MAXSIZE (1 << 20)
#define isdigit(x) (x >= '0' && x <= '9')
  char buf[MAXSIZE], *p1, *p2;
  char pbuf[MAXSIZE], *pp;
#if DEBUG
#else
  IO() : p1(buf), p2(buf), pp(pbuf) {}

  ~IO() { fwrite(pbuf, 1, pp - pbuf, stdout); }
#endif
  char gc() {
#if DEBUG
    return getchar();
#endif
    if (p1 == p2) p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin);
    return p1 == p2 ? ' ' : *p1++;
  }
  bool blank(char ch) {
    return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
  }
  template <class T>
  void read(T &x) {
    double tmp = 1;
    bool sign = 0;
    x = 0;
    char ch = gc();
    for (; !isdigit(ch); ch = gc())
      if (ch == '-') sign = 1;
    for (; isdigit(ch); ch = gc()) x = x * 10 + (ch - '0');
    if (ch == '.')
      for (ch = gc(); isdigit(ch); ch = gc())
        tmp /= 10.0, x += tmp * (ch - '0');
    if (sign) x = -x;
  }
  void read(char *s) {
    char ch = gc();
    for (; blank(ch); ch = gc())
      ;
    for (; !blank(ch); ch = gc()) *s++ = ch;
    *s = 0;
  }
  void read(char &c) {
    for (c = gc(); blank(c); c = gc())
      ;
  }
  void push(const char &c) {
#if DEBUG
    putchar(c);
#else
    if (pp - pbuf == MAXSIZE) fwrite(pbuf, 1, MAXSIZE, stdout), pp = pbuf;
    *pp++ = c;
#endif
  }
  template <class T>
  void write(T x) {
    static T sta[35];
    T top = 0;
    do {
      sta[top++] = x % 10, x /= 10;
    } while (x);
    while (top) push(sta[--top] + '0');
  }
  template <class T>
  void write(T x, char lastChar) {
    write(x), push(lastChar);
  }
} io;
struct Que{
	int l,r,k,id;
}q[300005];
inline int cmpq(Que x,Que y){
	return x.k<y.k;
}
int n,m,V,T,a[300005],b[300005],c[300005],ans[300005],lv[100005],rv[100005],lp[100005],rp[100005];
int siz,num,bel[300005],L[635],R[635],pr[635][635],sf[635][635],Log[635],f[12][635];
inline int qry(int l,int r){
	int il=bel[l],ir=bel[r],o=Log[(ir-1)-(il+1)+1];
	if(ir-il==1)return min(sf[il][l-L[il]+1],pr[ir][r-L[ir]+1]);
	return min({sf[il][l-L[il]+1],pr[ir][r-L[ir]+1],f[o][(il+1)],f[o][(ir-1)-(1<<o)+1]});
}
inline void solve(int k){
	for(int i=1;i<=n;++i)c[i]=a[i]%k;
	for(int i=1;i<=num;++i){
		pr[i][1]=c[L[i]];
		for(int j=L[i]+1;j<=R[i];++j)pr[i][j-L[i]+1]=min(pr[i][j-L[i]],c[j]);
		sf[i][R[i]-L[i]+1]=c[R[i]];
		for(int j=R[i]-1;j>=L[i];--j)sf[i][j-L[i]+1]=min(sf[i][j-L[i]+2],c[j]);
	}
	for(int i=1;i<=num;++i)f[0][i]=pr[i][R[i]-L[i]+1];
	for(int j=1;j<=Log[num];++j){
		for(int i=1;i+(1<<j)-1<=num;i++){
			f[j][i]=min(f[j-1][i],f[j-1][i+(1<<(j-1))]);
		}
	}
	for(int x=lv[k];x<=rv[k];++x)if(q[x].r-q[x].l+1>siz)ans[q[x].id]=qry(q[x].l,q[x].r);
}
inline int cmpa(int x,int y){
	return a[x]>a[y];
}
signed main(){
	io.read(n),io.read(m),siz=630,num=(n+siz-1)/siz;
	for(int i=1;i<=n;++i)bel[i]=(i-1)/siz+1;
	for(int i=1;i<=num;++i)L[i]=(i-1)*siz+1,R[i]=i*siz;
	R[num]=n;
	Log[1]=0;for(int i=2;i<=num+2;++i)Log[i]=Log[i>>1]+1;
	for(int i=1;i<=n;++i)io.read(a[i]),V=max(V,a[i]),b[i]=i;
	for(int i=1;i<=m;++i)io.read(q[i].l),io.read(q[i].r),io.read(q[i].k),q[i].id=i,ans[i]=inf;
	sort(q+1,q+m+1,cmpq);sort(b+1,b+n+1,cmpa);
	for(int i=1;i<=n;++i)lp[a[b[i]]]=(lp[a[b[i]]]?lp[a[b[i]]]:i),rp[a[b[i]]]=i;
	for(int i=1;i<=m;++i){
		int l=q[i].l,r=q[i].r,k=q[i].k,id=q[i].id;T=max(T,k);
		if(r-l+1<=siz){
			for(int j=l;j<=r;++j)ans[id]=min(ans[id],a[j]%k);
			continue;
		}
		lv[k]=(lv[k]?lv[k]:i),rv[k]=i;
	}
	int w=3*n+siz*Log[siz]-n*siz/m;
	for(int i=1;i<=T;++i)if(w<2.7*(V/i-1)*(rv[i]-lv[i]+1))solve(i),lv[i]=0;
	for(int i=1;i<=num;++i)for(int j=1;j<=R[i]-L[i]+1;++j)pr[i][j]=sf[i][j]=inf;
	for(int j=0;j<=Log[num];++j)for(int i=1;i+(1<<j)-1<=num;++i)f[j][i]=inf;
	for(int i=V;i>=1;i--){
		for(int x=lp[i];x<=rp[i];++x){
			int p=b[x],id=bel[p];
			for(int i=p;i<=R[id];++i)pr[id][i-L[id]+1]=a[p];
			for(int i=L[id];i<=p;++i)sf[id][i-L[id]+1]=a[p];
			for(int j=0;j<=Log[num];++j){
				int lt=max(1,id-(1<<j)+1),rt=min(id,num-(1<<j)+1);
				for(int i=lt;i<=rt;++i)f[j][i]=a[p];
			}
		}
		for(int j=1;j*j<=i;++j){
			if(i%j)continue;
			if(lv[j]){
				for(int x=lv[j];x<=rv[j];++x){
					int l=q[x].l,r=q[x].r,id=q[x].id;
					if(r-l+1>siz)ans[id]=min(ans[id],qry(l,r)-i);
				}
			}
			if(lv[i/j]&&i/j!=j){
				for(int x=lv[i/j];x<=rv[i/j];++x){
					int l=q[x].l,r=q[x].r,id=q[x].id;
					if(r-l+1>siz)ans[id]=min(ans[id],qry(l,r)-i);
				}
			}
		}
	}
	for(int i=1;i<=m;++i){
		int l=q[i].l,r=q[i].r,id=q[i].id;
		if(r-l+1>siz&&lv[q[i].k])ans[id]=min(ans[id],qry(l,r));
	}
	for(int i=1;i<=m;++i)io.write(ans[i],'\n');
	return 0;
}