[gym102770L]List of Products
有一个很重要的性质:若$a\le b$且$c\le d$,则$ac\le bd$
根据这一性质,就可以利用单调性$o(n)$求出小于$a_{x}\cdot b_{y}$的数的个数(先要对$a$和$b$排序)
考虑二分答案,假设答案$ans$满足$l\le ans\le r$,枚举$a_{i}$,利用单调性求出使得$l\le a_{i}\cdot b_{j}\le r$中间的$j$的区间,之后在所有数中随机选择一个作为$mid$,然后统计出比其小的数个数并与$k$判断
考虑时间复杂度,设对于$l$个数,答案为第$k$个,期望变短的长度为$\frac{k^{2}+(l-k)^{2}}{2l}\ge \frac{l}{4}$,即长度期望变为$o(\frac{3}{4}l)$,那么复杂度就是$o(\log_{\frac{4}{3}}nm)=o(\log_{2}mn)=o(\log_{2}n)$
最终时间复杂度为$o(n\sqrt{v}+n\log_{2}n(\log_{2}n+\log_{2}v))$(其中$v$为权值范围,后面的$\log_{2}v$为排序复杂度)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 struct ji{ 5 vector<int>v; 6 bool operator < (const ji &k){ 7 int s=min(v.size(),k.v.size()); 8 for(int i=0;i<s;i++) 9 if (v[i]!=k.v[i])return v[i]>k.v[i]; 10 return v.size()<k.v.size(); 11 } 12 bool operator == (const ji &k){ 13 if (v.size()!=k.v.size())return 0; 14 for(int i=0;i<v.size();i++) 15 if (v[i]!=k.v[i])return 0; 16 return 1; 17 } 18 }o,a[N],b[N]; 19 int t,n,m,x,y,st[N],ed[N]; 20 long long k; 21 ji div(int k){ 22 o.v.clear(); 23 for(int i=2;i*i<=k;i++) 24 while (k%i==0){ 25 k/=i; 26 o.v.push_back(i); 27 } 28 if (k>1)o.v.push_back(k); 29 return o; 30 } 31 ji merge(ji x,ji y){ 32 o.v.clear(); 33 for(int i=0,j=0;(i<x.v.size())||(j<y.v.size());) 34 if ((i!=x.v.size())&&((j==y.v.size())||(x.v[i]<y.v[j])))o.v.push_back(x.v[i++]); 35 else o.v.push_back(y.v[j++]); 36 return o; 37 } 38 int query(ji k){ 39 int ans=0; 40 for(int i=1,j=m;i<=n;i++){ 41 while ((j)&&(k<merge(a[i],b[j])))j--; 42 ans+=j; 43 } 44 return ans; 45 } 46 int sum(ji k){ 47 int ans=0; 48 for(int i=1,j=m;i<=n;i++){ 49 while ((j)&&(k<merge(a[i],b[j])))j--; 50 int s_i=i,s_j=j; 51 while ((j)&&(k==merge(a[s_i],b[j])))j--; 52 while ((i)&&(k==merge(a[i],b[s_j])))i++; 53 ans+=(i-s_i)*(s_j-j); 54 } 55 return ans; 56 } 57 long long calc(ji k){ 58 long long ans=1; 59 for(int i=0;i<k.v.size();i++)ans*=k.v[i]; 60 return ans; 61 } 62 int main(){ 63 srand(time(0)); 64 scanf("%d",&t); 65 while (t--){ 66 scanf("%d%d%lld",&n,&m,&k); 67 for(int i=1;i<=n;i++){ 68 scanf("%d",&x); 69 a[i]=div(x); 70 } 71 for(int i=1;i<=m;i++){ 72 scanf("%d",&x); 73 b[i]=div(x); 74 } 75 sort(a+1,a+n+1); 76 sort(b+1,b+m+1); 77 ji l=merge(a[1],b[1]),r=merge(a[n],b[n]); 78 while (1){ 79 int tot=0; 80 st[0]=ed[0]=m; 81 for(int i=1;i<=n;i++){ 82 st[i]=st[i-1]; 83 while ((st[i]>1)&&(!(merge(a[i],b[st[i]-1])<l)))st[i]--; 84 ed[i]=ed[i-1]; 85 while ((ed[i])&&(r<merge(a[i],b[ed[i]])))ed[i]--; 86 tot+=ed[i]-st[i]+1; 87 } 88 if (tot==sum(l)+sum(r))break; 89 tot=rand()%tot+1; 90 for(int i=1;i<=n;i++) 91 if (ed[i]-st[i]+1<tot)tot-=ed[i]-st[i]+1; 92 else{ 93 x=i; 94 y=st[i]+tot-1; 95 break; 96 } 97 ji mid=merge(a[x],b[y]); 98 if (query(mid)<=k)l=mid; 99 else r=mid; 100 } 101 long long ans=1; 102 for(int i=0;i<l.v.size();i++)ans*=l.v[i]; 103 printf("%lld\n",ans); 104 } 105 }