Codeforces 1684G - Euclid Guess(网络流)
作者:互联网
煞笔题,我是什么煞笔,在这么煞笔的比赛中没有做出这么煞笔的题?
(u1s1 其实感觉这道题还挺有意思的)
首先对于一个数 \(t\),要想得到 \(t\) 为余数,除数至少是 \(t+1\),这样 \(a\) 就至少是 \(2t+1\),因此如果存在 \(2t_i+1>m\) 就直接输出 \(-1\) 好了。我们还可以发现,对于一个满足 \(3t\le m\) 的数,我们可以通过直接构造 \((3t,2t)\) 将其消去并且不会影响到其他数,但是对于 \(3t>m\) 的数就不能这样构造了。换而言之,要想消掉一个 \(3t>m\) 的 \(t\),我们需要选择一个 \(k\) 使得 \(2t+k\le m\),并构造 \((2t+k,t+k)\),这样可以消掉 \(t\) 并进而对 \((t,k)\) 进行辗转相除。因此我们可以想到一个很自然的想法:先用 \(3t\le m\) 的小 t 消去 \(3t>m\) 的大 t,剩余的小 t 直接 \((3t,2t)\) 带走。
但是对于一个大 t 我们又该选择怎样的 \(k\) 呢?贪心?好像没法贪。不过我们注意到一个性质,就是最终 \(\gcd(t,k)\) 肯定会在辗转相除得到的序列中,因此我们不妨就令 \(k=\gcd(t,k)\),即 \(k\mid t\),这样会恰好消除 \(k,t\) 两个数,感性理解这样肯定最优,因此我们考虑在符合 \(t_j\mid t_i\),\(3t_i>m,3t_j\le m\) 的 \(i,j\) 之间连边,然后跑最大匹配,由于是二分图,最大匹配容易求得,如果最大匹配不等于大 t 数量则无解,否则根据前面的过程构造出解即可。
const int MAXN = 1e3;
const int MAXE = 2e6;
const int INF = 0x3f3f3f3f;
int n, m, a[MAXN + 5];
int S, T, hd[MAXN + 5], to[MAXE + 5], nxt[MAXE + 5], cap[MAXE + 5], ec = 1;
void adde(int u, int v, int f) {
to[++ec] = v; cap[ec] = f; nxt[ec] = hd[u]; hd[u] = ec;
to[++ec] = u; cap[ec] = 0; nxt[ec] = hd[v]; hd[v] = ec;
}
int dep[MAXN + 5], now[MAXN + 5];
bool getdep(int S, int T) {
memset(dep, -1, sizeof(dep)); queue<int> q;
q.push(S); dep[S] = 0;
while (!q.empty()) {
int x = q.front(); q.pop(); now[x] = hd[x];
for (int e = hd[x]; e; e = nxt[e]) {
int y = to[e], z = cap[e];
if (z && dep[y] == -1) {
dep[y] = dep[x] + 1;
q.push(y);
}
}
}
return ~dep[T];
}
int getflow(int x, int f) {
if (x == T) return f; int ret = 0;
for (int &e = now[x]; e; e = nxt[e]) {
int y = to[e], z = cap[e];
if (z && dep[y] == dep[x] + 1) {
int w = getflow(y, min(f - ret, z));
cap[e] -= w; cap[e ^ 1] += w; ret += w;
if (ret == f) return ret;
}
}
return ret;
}
int dinic() {
int ret = 0;
while (getdep(S, T)) ret += getflow(S, INF);
return ret;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (2 * a[i] + 1 > m) return puts("-1"), 0;
}
T = (S = n + 1) + 1;
int cnt = 0;
for (int i = 1; i <= n; i++) if (3ll * a[i] > m) {
for (int j = 1; j <= n; j++) if (3ll * a[j] <= m && a[i] % a[j] == 0 && 2ll * a[i] + a[j] <= m)
adde(i, j, 1);
cnt++;
}
for (int i = 1; i <= n; i++) {
if (3ll * a[i] > m) adde(S, i, 1);
else adde(i, T, 1);
}
if (dinic() != cnt) return puts("-1"), 0;
vector<pii> res;
for (int i = 1; i <= n; i++) if (3ll * a[i] > m) {
for (int e = hd[i]; e; e = nxt[e]) {
int y = to[e];
if (to[e] != S && !cap[e]) res.pb(mp(2 * a[i] + a[y], a[i] + a[y]));
}
}
for (int i = 1; i <= n; i++) if (3ll * a[i] <= m) {
for (int e = hd[i]; e; e = nxt[e]) {
int y = to[e];
if (y == T && cap[e]) res.pb(mp(3 * a[i], 2 * a[i]));
}
}
printf("%d\n", (int)(res.size()));
for (pii p : res) printf("%d %d\n", p.fi, p.se);
return 0;
}
标签:dep,int,Codeforces,ret,3t,1684G,ec,Euclid,hd 来源: https://www.cnblogs.com/ET2006/p/Codeforces-1684G.html