CF1656H 做题记录
很强的一道题。
发现值域达到了恐怖的 \(4\times 10^{36}\),即使用 Pollard-Rho 都分解不了一个质因数。
我们考虑使用调整法,在给出的全集中删掉一些数来构造答案。
考虑一个数需要删掉的条件。设需要删掉 \(a_i\),若其中的一个质因数 \(p\) 满足 \(a_i\) 的次数比 \(b_{1...m}\) 都要大,那么 \(a_i\) 一定要删。
这是必要的。运用调整法的思想,我们不断删数,重复若干轮,直到找不到可以删的数,这是充要的。
但是质因数是不能分解的,注意到上述条件相当于:\(\gcd\limits_{1\le j\le m}\{\dfrac {a_i} {\gcd(a_i,b_j)}\}>1\)。
发现式子是对的,于是每轮枚举删除的数字,并判定是否满足条件。
但是复杂度来到了 \(O(n^3)\),考虑每次删掉一个数字后,会对对面集合里的数字产生的影响是:少了一个数值参与 \(\gcd\) 运算。
于是每个数字开一棵线段树维护 \(\gcd\) 即可。
总结一下:
-
观察关键条件,主要是充要条件。
-
寻找等价条件,把不可做变成可做。
-
微调的优化
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define mkp make_pair
#define pir pair<ll,ll>
#define ull unsigned ll
#define pb push_back
#define i128 __int128
using namespace std;
const ll maxn=1010;
ll t,n,m;
i128 a[maxn], b[maxn], w[maxn];
i128 gcd(i128 a,i128 b) {return !b? a:gcd(b,a%b);}
struct SGT{
i128 g[maxn<<2];
void build(ll p,ll l,ll r,i128 *a){
if(l==r) {g[p]=a[l]; return;}
ll mid=l+r>>1;
build(p<<1,l,mid,a), build(p<<1|1,mid+1,r,a);
g[p]=gcd(g[p<<1],g[p<<1|1]);
}
void modify(ll p,ll l,ll r,ll x){
if(l==r) {g[p]=0; return;}
ll mid=l+r>>1;
if(x<=mid) modify(p<<1,l,mid,x);
else modify(p<<1|1,mid+1,r,x);
g[p]=gcd(g[p<<1],g[p<<1|1]);
}
}tr_a[maxn],tr_b[maxn];
ll vis_a[maxn], vis_b[maxn];
ll cnt_a, cnt_b;
void read(i128 &x){
char c;
while(!isdigit(c=getchar())) ;
x=c-'0';
while(isdigit(c=getchar())) x=(x<<1)+(x<<3)+c-'0';
}
void write(const i128 x){
if(x>9) write(x/10);
putchar(x%10+'0');
}
int main(){
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++) read(a[i]), vis_a[i]=1;
for(ll i=1;i<=m;i++) read(b[i]), vis_b[i]=1;
for(ll i=1;i<=n;i++){
for(ll j=1;j<=m;j++) w[j]=a[i]/gcd(a[i],b[j]);
tr_a[i].build(1,1,m,w);
}
for(ll i=1;i<=m;i++){
for(ll j=1;j<=n;j++) w[j]=b[i]/gcd(b[i],a[j]);
tr_b[i].build(1,1,n,w);
} cnt_a=n, cnt_b=m;
while(1){
ll flg=0;
for(ll i=1;i<=n;i++)
if(vis_a[i]&&tr_a[i].g[1]!=1){
for(ll j=1;j<=m;j++)
if(vis_b[j]) tr_b[j].modify(1,1,n,i);
flg=1, vis_a[i]=0, --cnt_a; break;
}
if(flg) continue;
for(ll i=1;i<=m;i++)
if(vis_b[i]&&tr_b[i].g[1]!=1){
for(ll j=1;j<=n;j++)
if(vis_a[j]) tr_a[j].modify(1,1,m,i);
flg=1, vis_b[i]=0, --cnt_b; break;
}
if(!flg) break;
}
if(!cnt_a||!cnt_b) {puts("NO"); continue;}
printf("YES\n%lld %lld\n",cnt_a,cnt_b);
for(ll i=1;i<=n;i++)
if(vis_a[i]) write(a[i]), putchar(' '); puts("");
for(ll i=1;i<=m;i++)
if(vis_b[i]) write(b[i]), putchar(' '); puts("");
}
return 0;
}

浙公网安备 33010602011771号