cf round 482D Kuro and GCD and XOR and SUM
题意:
开始有个空集合,现在有两种操作:
$(1,x)$:给集合加一个数$x$,$x \leq 10^5$;
$(2,x,k,s)$:在集合中找一个$a$,满足$a \leq s-x$,而且$k|gcd(a,x)$;现在需要找满足条件的$a$,它异或$x$的值最大。$x,k,s \leq 10^5$
操作数$q \leq 10^5$
这道题就是看你想到一个算法有没有去算算实际复杂度
我们发现,对于所有在$[1,10^5]$的$i$,$10^5$之内的$i$的倍数的个数和,并不是很大,只有$2*10^7$左右
然后就维护$10^5$个trie就好了……
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=2e5+7,maxm=2e7+7,W=1e5,U=16,INF=0x3f3f3f3f; int n,root[maxn],tot=W; int son[maxm][2],minnum[maxm]; bool vis[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int prime[maxn],totp,num[maxn]; bool ok[maxn]; void get_p() { For(i,2,W) { if(!ok[i]) prime[++totp]=i,num[i]=i; For(j,1,totp) { if(prime[j]>W/i) break; ok[i*prime[j]]=1; num[i*prime[j]]=prime[j]; if(i%prime[j]==0) break; } } } void add(int pos,int x) { minnum[pos]=min(minnum[pos],x); int r; Rep(i,U,0) { r=(x>>i)&1; if(!son[pos][r]) minnum[son[pos][r]=++tot]=x; pos=son[pos][r]; minnum[pos]=min(minnum[pos],x); } } int zz[maxn]; void get_add(int x) { if(vis[x]) return; vis[x]=1; int s=1,t=1,p,now,y,o=x; zz[1]=1; while(x!=1) { p=num[x]; now=0; y=1; while(x%p==0) x/=p,now++; For(i,1,now) { y*=p; For(j,1,s) zz[++t]=zz[j]*y; } s=t; } For(i,1,t) add(zz[i],o); } int get_ans(int x,int pos,int v) { if(x%pos||minnum[pos]>v) return -1; int r; Rep(i,U,0) { r=(x>>i)&1; if(minnum[son[pos][r^1]]<=v) pos=son[pos][r^1]; else pos=son[pos][r]; } return minnum[pos]; } int main() { read(n); int op,k,x,v; get_p(); For(i,0,W) minnum[i]=INF; For(i,1,n) { read(op); read(x); if(op==1) get_add(x); else { read(k); read(v); printf("%d\n",get_ans(x,k,v-x)); } } return 0; }
弱者就是会被欺负呀