Loading

CF1656H 做题记录

link

很强的一道题。

发现值域达到了恐怖的 \(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;
}
posted @ 2024-05-06 11:51  Sktn0089  阅读(18)  评论(0)    收藏  举报