0%

BZOJ 4320: ShangHai2006 Homework

1:在人物集合 S 中加入一个新的程序员,其代号为 X,保证 X 在当前集合中不存在。 2:在当前的人物集合中询问程序员的mod Y 最小的值。 (为什么统计这个?因为拯救过世界的人太多了,只能取模) N≤100000, 1≤X,Y≤300000

对于询问的\(Y\)进行分块,如果\(Y \le \sqrt{300000}\),开一个数组进行暴力维护 如果\(Y \ge \sqrt{300000}\),枚举每一个\(k \times Y\),找到\(\ge k \times Y\)的最小值,取余就是答案。 找最小值的话,似乎可以用set? 也可以用并查集,每一个数字的father就是在数字集合中出现的第一个大于等于他的数字,正着做的话要不停的插入,比较麻烦,倒着做只有删除操作,比较简单。而且比set的方法少一个\(log\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include<bits/stdc++.h>
using namespace std;
int n;
char c[100010]={};
int x[100010]={};
int ans[100010]={};
bool nu[300010]={};
int fa[300010]={};
int q[610]={};
int ff(int x)
{
if(x==fa[x]) return x;
fa[x]=ff(fa[x]);
return fa[x];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=600;i++)
{
q[i]=2147483600;
}
for(int i=1;i<=n;i++)
{
c[i]=getchar();
while(c[i]!='A'&&c[i]!='B')
{
c[i]=getchar();
}
scanf("%d",&x[i]);
if(c[i]=='A')
{
nu[x[i]]=1;
for(int j=1;j<=600;j++)
{
q[j]=min(q[j],x[i]%j);
}
}
else
{
if(x[i]<=600) ans[i]=q[x[i]];
}
}
fa[300001]=300001;
for(int i=300000;i>=0;i--)
{
if(nu[i]==1) fa[i]=i;
else
{
fa[i]=i+1;
ff(i);
}
}
for(int i=n;i>=1;i--)
{
if(c[i]=='A')
{
fa[x[i]]=x[i]+1;
ff(x[i]);
}
else if(x[i]>600)
{
int o=2147483600;
int k=0;
while(1)
{
if(k*x[i]>300000) break;
int t=ff(k*x[i]);
if(t==300001) break;
o=min(o,t%x[i]);
k++;
}
ans[i]=o;
}
}
for(int i=1;i<=n;i++)
{
if(c[i]=='B')
{
printf("%d\n",ans[i]);
}
}
return 0;
}