题意简述
初始有一个空的集合,和
Q
Q
Q个操作。对于每个操作,有两种类型,分别用如下的两种形式表示:
1
u
1\ u
1 u:加入
u
u
u到集合
2
x
k
s
2\ x\ k\ s
2 x k s:求一个最大的
v
v
v,使得:
- v + x < s v+x<s v+x<s
- k ∣ g c d ( v , x ) k∣gcd(v,x) k∣gcd(v,x)
-
x
⊕
v
x \oplus v
x⊕v最大(其中
⊕
\oplus
⊕表示按位异或,对应
C
+
+
C++
C++中的^运算符)
如果找不到满足条件的 v v v,输出 − 1 −1 −1
数据
输入
第一行是一个正整数
Q
Q
Q。
接下来
Q
Q
Q行,每行一个操作,如题意简述中所描述。
输出
对于每个 2 2 2操作,输出答案,或者 − 1 -1 −1。
思路
首先我们要明确一个问题:如果没有任何限制,只是求异或和最大,怎么求?
这是一个非常经典的问题:最大异或对。我们采用 01 − T R I E 01-TRIE 01−TRIE按位跑一遍,每次贪心选择,求出答案。珂是 T R I E TRIE TRIE虽然好理解,但是不好写,如果一不小心写挂了,就要浪费不少时间。而且, C F CF CF上也很提倡一题多解,支持各种玄学方法,时间很足,空间也足,只要不是暴力,都过得去。
所以我们想到用 S T L STL STL的 s e t set set乱搞,看能不能过这个题。准确来讲,我的这个算法是 O ( n 2 ) O(n^2) O(n2)的,但是要知道几点,
- C F CF CF机快
- 数据水
- 这题时限 2 s 2s 2s
综上, O ( n 2 ) O(n^2) O(n2)能过。所以,我们用 s e t set set开个数组, s e t < i n t > r e c [ N ] set<int>rec[N] set<int>rec[N], r e c [ i ] rec[i] rec[i]表示给定的数中是 i i i的倍数的那些。然后,我们在询问的时候,在 r e c [ i ] rec[i] rec[i]中找到最后一个 < s − x <s-x <s−x的位置(即 u p p e r _ b o u n d ( s − x ) − 1 upper\_bound(s-x)-1 upper_bound(s−x)−1),暴力枚举,看看哪个最大。当然记得判边界。事实证明这非常快,能 A C AC AC。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
#define N 100100
set<int> rec[N];
set<int>::iterator It;//一个临时迭代器
void Insert(int x)
{
for(int i=1;i*i<=x;++i)
{
if (x%i==0)
{
rec[i].insert(x);
rec[x/i].insert(x);
}
}//每次要枚举x的因数,都去存一下
}
int calc(int x,int k,int s)
{
if (x%k!=0) return -1;
if (rec[k].size()==0) return -1;//剪枝(没啥用)
It=rec[k].upper_bound(s-x);
if (It==rec[k].begin()) return -1;
//如果It==rec[k].begin(),那么-1会很危险,特判
--It;
int ans=-1,sum=-1;
for(;It!=rec[k].begin();--It)//暴力
{
int tmp=*It;
if (sum>x+tmp) break;
if ((tmp^x)>sum)
{
sum=tmp^x;
ans=tmp;//更新答案
}
}
if ((x^(*rec[k].begin()))>sum) ans=*rec[k].begin();
//begin特判
return ans;
}
void Query()
{
int q;scanf("%d",&q);
while(q--)
{
int o;scanf("%d",&o);
if (o==1)
{
int x;scanf("%d",&x);
Insert(x);
}
else if (o==2)
{
int x,k,s;
scanf("%d%d%d",&x,&k,&s);
printf("%d\n",calc(x,k,s));
}
}
}
void Main()
{
if (0)
{
freopen("","r",stdin);
freopen("","w",stdout);
}
Query();
}
};
main()
{
Flandle_Scarlet::Main();
return 0;
}