[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 }
View Code

 

posted @ 2020-10-23 07:50  PYWBKTDA  阅读(388)  评论(2编辑  收藏  举报