Fishermen CF1728F题解
首先,对于每个数
考虑到最坏情况就是,这
再想贪心,因为要令和最小,则将所有倍数从小到大排序作为左部点,所有
考虑为什么这样贪心是对的——
我们每次都选择当前最小的倍数,设该倍数为
如果该倍数匹配成功,设该倍数为
综上所述,该贪心正确。
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; }