CodeTON Round 1 (Div. 1 + Div. 2, Rated)

F.Parametric MST

题目描述

点此看题

解法

现在菜到连 \(2600\) 的题目都做不起了,难受。

首先考虑如何判断答案为 INF,考虑所有方案对应 \(t\) 的系数,如果系数只有正或者只有负,那么一定可以通过设置 \(t\) 使得答案为 INF

接着考虑固定 \(t\) 之后如何计算答案,我们可以把代价改写成 \((a_i+t)(a_j+t)-t^2\),减去的项是常数,所以我们令 \(a_i\leftarrow a_i+t\),那么此时的 \(a\) 数组一定有正有负。我们把 \(a\) 从小到大排序,然后考虑贪心,也就是把所有正数和 \(a_1\) 相连,把所有负数和 \(a_n\) 相连。

那么问题变成了确定 \(t\),有一个关键的 \(\tt observation\) 是:可能的 \(t\) 的取值是 \(a_1,a_2...a_n\),这是因为首先 \(t\) 的取值范围在 \([-a_n,-a_1]\)(要保证有正有负),然后如果 \(t\) 不取端点值,由于此时的方案是固定的,那么调整到临近的端点值一定更优,时间复杂度 \(O(n\log n)\)

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 200005;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int T,n,ans,a[M],b[M];
int work(int x,int t)
{
	return (a[1]+t)*(b[n-1]-b[x]+t*(n-x-1))
		+(a[n]+t)*(b[x]+t*x)-t*t*(n-1);
}
void work()
{
	n=read();ans=-1e18;
	for(int i=1;i<=n;i++)
		a[i]=read();
	sort(a+1,a+1+n);
	for(int i=1;i<=n;i++)
		b[i]=b[i-1]+a[i];
	if(a[1]*(n-2)+b[n]>0 || a[n]*(n-2)+b[n]<0)
	{
		puts("INF");
		return ;
	}
	for(int i=1;i<n;i++)
		ans=max(ans,work(i,-a[i]));
	printf("%lld\n",ans);
}
signed main()
{
	T=read();
	while(T--) work();
}

H.Equal LCM Subsets

题目描述

点此看题

有一个大小为 \(n\) 的集合 \(A\),有一个大小为 \(m\) 的集合 \(B\),构造 \(A\) 的子集和 \(B\) 的子集,使得它们的 \(\tt lcm\) 相等。

\(n,m\leq 1000\)\(a_i,b_i\leq 4\cdot 10^{36}\)

解法

考虑把问题变成:从 \(A\)\(B\) 中删除一些数,使得剩下的数 \(\tt lcm\) 相等。

考虑如果一个数需要被删除的条件,就是它的某个质数次幂大于另一个集合中对应质数次幂的最大值,由于本题不支持质因数分解,所以我们转化成下列形式:

\[\gcd_{i=1}^n\frac{a_x}{\gcd(a_x,b_i)}>1 \]

那么对于每一个位置都开一棵线段树维护 \(\gcd\),这样就可以在删除的时候支持修改了,时间复杂度 \(O(n^2\log n\log a)\)

#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
#define int __int128
const int M = 1005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
void write(int x)
{
	if(x>=10) write(x/10);
	putchar(x%10+'0');
}
int T,n,m,a[2][M],b[2][M],c[2],d[2];
int gcd(int a,int b) {return !b?a:gcd(b,a%b);}
struct node {int x,y;};queue<node> q;
struct tree
{
	int t[M<<2];
	void build(int i,int l,int r,int f,int x)
	{
		if(l==r) {t[i]=x/gcd(a[f][l],x);return ;}
		int mid=(l+r)>>1;
		build(i<<1,l,mid,f,x);
		build(i<<1|1,mid+1,r,f,x);
		t[i]=gcd(t[i<<1],t[i<<1|1]);
	}
	void rem(int i,int l,int r,int x)
	{
		if(l==r) {t[i]=0;return ;}
		int mid=(l+r)>>1;
		if(mid>=x) rem(i<<1,l,mid,x);
		else rem(i<<1|1,mid+1,r,x);
		t[i]=gcd(t[i<<1],t[i<<1|1]);
	}
	int ask() {return t[1]>1;}
}f[2][M];
void work()
{
	n=read();m=read();
	c[0]=n;c[1]=m;d[0]=d[1]=0;
	for(int i=1;i<=n;i++) a[0][i]=read(),b[0][i]=0;
	for(int i=1;i<=m;i++) a[1][i]=read(),b[1][i]=0;
	for(int w=0;w<2;w++)
		for(int i=1;i<=c[w];i++)
		{
			f[w][i].build(1,1,c[w^1],w^1,a[w][i]);
			if(f[w][i].ask())
				q.push({w,i}),b[w][i]=1,d[w]++;
		}
	while(!q.empty())
	{
		int w=q.front().x,i=q.front().y;q.pop();
		for(int j=1;j<=c[w^1];j++) if(!b[w^1][j])
		{
			f[w^1][j].rem(1,1,c[w],i);
			if(f[w^1][j].ask())
				q.push({w^1,j}),b[w^1][j]=1,d[w^1]++;
		}
	}
	if(c[0]==d[0] || c[1]==d[1]) {puts("NO");return ;}
	puts("YES");
	write(c[0]-d[0]);putchar(' ');
	write(c[1]-d[1]);puts("");
	for(int w=0;w<2;w++,puts(""))
		for(int i=1;i<=c[w];i++) if(!b[w][i])
			write(a[w][i]),putchar(' ');
}
signed main()
{
	T=read();
	while(T--) work();
}
posted @ 2022-04-28 13:09  C202044zxy  阅读(145)  评论(1编辑  收藏  举报