Fishermen CF1728F题解

题目传送门

首先,对于每个数 \(a\),都能与自己的倍数匹配,我们只需要令每个数所能匹配到的倍数的和最小,又因为每个数只能用一次,\(a\)\(a\) 的倍数是一一对应的关系,所以我们想到二分图匹配。

考虑到最坏情况就是,这 \(n\) 个数都相同,那么最大匹配的就是 \(a\times n\),同时如果每个数的 \([a, a^2]\) 没有交集,则我们实际上会产生最多 \(n^2\) 个倍数。

再想贪心,因为要令和最小,则将所有倍数从小到大排序作为左部点,所有 \(a\) 作为右部点,从左到右扫一遍倍数集合,如果有匹配则令结果加上该倍数。注意当匹配数等于 \(n\) 时退出。

考虑为什么这样贪心是对的——

我们每次都选择当前最小的倍数,设该倍数为 \(u\),如果 \(u\) 匹配不上,说明右侧的数集中与之相连的数都已匹配,且右侧数集匹配的左部点无法增广,即右部点中未匹配的数没有左部点的因数。同时左部点中已匹配的点都是比 \(u\) 小的,这时候,如果在答案中加入 \(u\),一定会使结果变大。

如果该倍数匹配成功,设该倍数为 \(u\),那么说明右侧有仍未匹配的数,设该数为 \(k\), \(k\) 无法匹配上之前比 \(u\) 更小的数,且匹配比 \(u\) 大的数一定会令结果变大。

综上所述,该贪心正确。

Code:

#include<bits/stdc++.h>
using namespace std;
const int N = 1050, M = 1e6+100;

inline int read()
{
	int x = 0; char ch = getchar();
	while(ch<'0'||ch>'9'){ch = getchar();}
	while(ch>='0'&&ch<='9'){x = x*10+ch-48; ch = getchar();}
	return x;
}

int head[N*N], tot;
struct node
{
	int nxt, to;
}edge[N*N*2];
void add(int u, int v)
{
	edge[++tot].nxt = head[u];
	edge[tot].to = v;
	head[u] = tot;
}
int n;
int a[N];
int rit[N*N+N], num;
int mat[N*N+N];
bool vis[N*N+N];


bool dfs(int u)
{
	for(int i = head[u]; i; i = edge[i].nxt)
	{
		int v = edge[i].to;
		if(vis[v]) continue;
		vis[v] = 1;
		if(!mat[v]||dfs(mat[v]))
		{
			mat[v] = u;
			return 1;
		}
	}
	return 0;
}
int xwx[N*N], qw; 
int main()
{
	n = read();
	for(int i = 1; i<=n; i++)
		a[i] = read();
	sort(a+1, a+n+1);
	num = n;
	int last = 0;
	for(int i = 1; i<=n; i++)
	{
		if(last == a[i]) continue;//去重
		last = a[i];
		for(int j = 1; j<=n; j++)
		{
			xwx[++qw] = a[i]*j;
		}
	}
	sort(xwx+1,xwx+qw+1);
	qw = unique(xwx+1, xwx+qw+1)-xwx-1;//还是去重,因为要离散化
	for(int i = 1; i<=n; i++)
		for(int j = n; j>=1; j--)
		{
			int pos = lower_bound(xwx+1, xwx+qw+1, a[i]*j)-xwx;
			add(pos+n, i);
		}
	for(int i = 1; i<=qw; i++)
	{
		rit[++num] = xwx[i];
	}
	long long ans = 0;
	for(int i = n, tt = 0; i <= num && tt <= n; i++)
	{
		if(dfs(i)) 
		{
			tt++;
			memset(vis, 0, sizeof(vis));
			ans+=rit[i];
		}
	}
	printf("%lld\n", ans);
	return 0;
}
posted @ 2023-06-07 10:36  霜木_Atomic  阅读(9)  评论(0编辑  收藏  举报