4320: ShangHai2006 Homework
分析:
分块。对权值模数进行分块,模数小于$sqrt V$的($V$为权值上界),暴力处理。
模数大于$sqrt V$的,设模数是k,枚举k的倍数,然后查询大于[k,2k]之间的最小的数x,这个区间的mod k最小的数就是x-k。k的倍数共有$sqrt V$个,每次查询,再对权值进行分块,并维护后缀最小值,做到$O(1)$查询。复杂度$O(n sqrt V)$
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 300000, M = 550, INF = 1e9; int bel[N + 5], tag[N + 5], f[N + 5], pt[N + 5]; void add(int x) { for (int i = 1; i <= M; ++i) f[i] = min(f[i], x % i); tag[bel[x]] = min(tag[bel[x]], x); pt[x] = min(pt[x], x); for (int i = x - 1, lim = (bel[x] - 1) * M; i >= lim; --i) pt[i] = min(pt[i], pt[i + 1]); for (int i = bel[x] - 1; i; --i) tag[i] = min(tag[i], tag[i + 1]); } int query(int x) { return min(pt[x], tag[bel[x] + 1]); } int Ask(int x) { if (x <= M) return f[x]; int ans = query(1) % x; for (int i = x; i <= N; i += x) { int t = query(i) - i; if (t < x) ans = min(ans, t); } return ans; } int main() { memset(f, 0x3f, sizeof(f)); memset(tag, 0x3f, sizeof(tag)); memset(pt, 0x3f, sizeof(pt)); int n = read(); for (int i = 1; i <= N; ++i) bel[i] = (i - 1) / M + 1; char opt[10]; for (int i = 1; i <= n; ++i) { scanf("%s", opt); int x = read(); if (opt[0] == 'A') add(x); else printf("%d ", Ask(x)); } return 0; }