[APIO2025] Hack!
题意大概是根据冲突次数问出来哈希模数。
实际上,本题中无需知道冲突次数,只需知道是否冲突。
考虑集合
也就是是否存在两个数
如果我们能构造出一个集合,使得所有能表示成这个集合中两数之差的数构成一个前缀,那么就可以通过二分答案求出
问题转化为对于给定的
一种经典的构造是取
这样总共需要
考虑优化。
这个做法的问题在于当我们二分的区间很小的时候,如果
考虑能否构造一个大小与区间长度相关的集合,从而查询这个区间内是否有
令
于是,我们的查询次数为
但是由于常数很大,无法通过。
注意到,由于
于是把初始二分区间设置为
这样可以获得神秘的
最后一个优化是可以直接试除
#include <bits/stdc++.h>
using namespace std;
#define int long long
int collisions(vector<int>q);
bool chk(int l,int r){
int y=sqrt(r-l)+1;
vector<int>q;
for(int i=1;i<=y;i++)q.push_back(i);
for(int i=y+l;i<=r;i+=y)q.push_back(i);
q.push_back(r+1);
return collisions(q);
}
signed hack(){
int l=5e8+1,r=1e9;
while(l<r){
int mid=l+r>>1;
if(chk(l,mid))r=mid;
else l=mid+1;
}
for(int i=2;i*i<=l;i++){
if(l%i==0){
while(l%i==0)l/=i;
while(r%i==0&&r!=i&&collisions({1,r/i+1}))r/=i;
}
}
while(l>1&&r%l==0&&r!=l&&collisions({1,r/l+1}))r/=l;
return r;
}