[gym102770L]List of Products
题意简述
我们根据唯一分解定理得到,对于每一个数
我们重新定义两个数之间的比较,对于两个数
-
如果
,两个数相等 -
如果
不相等,我们就从小到大枚举素数,知道找到一个下标 满足对于 两个数的 相等,但是 不相等。 大的更大。比如 。
我们现在有两个序列,长度分别为
思路点拨
我们考虑到一个性质:
因为
但是实际上,在二分的过程中我们需要选择一个节点
还是利用单调性。这一点可以留给读者自己思考。
代码
原题对常数的要求比较严格,我的这份代码并不可以通过,仅供参考:
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-f;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int MAXN=5e5+10;
int n,m,k;
struct node{
vector<int> p;//质因子
void clear(){p.clear();}
bool friend operator<(const node &A,const node &B){
int len=min(A.p.size(),B.p.size());
for(int i=0;i<len;i++){
if(A.p[i]==B.p[i]) continue;
else return A.p[i]>B.p[i];
}
return A.p.size()<B.p.size();
}
bool friend operator==(const node &A,const node &B){
if(A.p.size()!=B.p.size())
return 0;
int len=A.p.size();
for(int i=0;i<len;i++){
if(A.p[i]==B.p[i]) continue;
return 0;
}
return 1;
}
bool friend operator>=(const node &A,const node &B){
if(A<B) return 0;
return 1;
}
}temp;
node merge(node x,node y){
temp.p.clear();
for(int i=0,j=0;(i<x.p.size())||(j<y.p.size());)
if ((i!=x.p.size())&&((j==y.p.size())||(x.p[i]<y.p[j])))temp.p.push_back(x.p[i++]);
else temp.p.push_back(y.p[j++]);
return temp;
}
const int N=1e6;
int vis[N+10];
vector<int> o[N];
void init(){
for(int i=2;i<=N;i++){
if(vis[i]) continue;
o[i].push_back(i);
for(int j=i*2;j<=N;j+=i){
vis[j]=1;
o[j].push_back(i);
}
}
}
node a[MAXN],b[MAXN];
node split(int x){
temp.clear();
int y=x;
for(int i=0;i<o[x].size();i++){
while(y%o[x][i]==0){
temp.p.push_back(o[x][i]);
y/=o[x][i];
}
}
return temp;
}
int ft[MAXN],ed[MAXN];
int run(node k){
int ans=0;
for(int i=1,j=m;i<=n;i++){
while (j&&(k<merge(a[i],b[j]))) j--;
int s_i=i,s_j=j;
while (j&&(k==merge(a[s_i],b[j]))) j--;
while (i&&(k==merge(a[i],b[s_j]))) i++;
ans+=(i-s_i)*(s_j-j);
}
return ans;
}
int fun(node A){
int ans=0;
for(int l=1,r=m;l<=n;l++){
while(r&&A<merge(a[l],b[r]))
r--;
ans+=r;
}
return ans;
}
int solve(){
node L=merge(a[1],b[1]),R=merge(a[n],b[m]);
while(1+1==2){
ft[0]=ed[0]=m;
int useful=0;//在二分的值域内存在的有用点对
for(int i=1;i<=n;i++){
ft[i]=ft[i-1],ed[i]=ed[i-1];
while(ft[i]>1&&!(merge(a[i],b[ft[i]-1])<L)) ft[i]--;
while(ed[i]&&R<merge(a[i],b[ed[i]])) ed[i]--;
useful+=(ed[i]-ft[i]+1);
}
if(useful==run(L)+run(R)) break;//此时[l,r]之间没有除了l,r之外的决策点
int kk=rand()%useful+1,l,r;
for(int i=1;i<=n;i++){
if(ed[i]-ft[i]+1<kk)
kk-=(ed[i]-ft[i]+1);
else{
l=i;
r=ft[i]+kk-1;
break;
}
}
node mid=merge(a[l],b[r]);
if(fun(mid)<=k) L=mid;
else R=mid;
}
int cnt=1;
for(int i=0;i<L.p.size();i++) cnt*=L.p[i];
return cnt;
}
signed main(){
srand(time(0));
int T=read();
init();//筛法
while(T--){
n=read(),m=read(),k=read();
for(int i=1;i<=n;i++){
int x=read();
a[i]=split(x);
}
for(int i=1;i<=m;i++){
int x=read();
b[i]=split(x);
}
sort(a+1,a+n+1);
sort(b+1,b+m+1);
cout<<solve()<<endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】