Solution - Atcoder ARC099E Independence

rizynvu發表於2024-07-31

首先考慮如何最小化團內邊數。
考慮到如果兩個團大小分別為 \(x\le y\),那麼有 \((\binom{x - 1}{2} + \binom{y + 1}{2}) - (\binom{x}{2} + \binom{y}{2}) = -x + 1 + y = y - x + 1 \ge 1\)
所以可以知道,當 \(|x - y|\) 越小時,團內邊數也最小。

接下來考慮如何求解團。
考慮到團的求解在 \(n\le 700\) 的情況下看起來並不是很好做,於是考慮轉化一下,不去求團。

考慮到題目中兩個團的條件。
一個啟發是想到二分圖的左部點右部點。
然後會發現左部點右部點內部需要滿足都沒有連邊,而團是要求內部都要有連邊。

於是能夠發現在補圖上的一個合法二分圖就對應著原圖上的兩個團。

那麼在補圖上跑出來的會有很多個二分圖。
現在相當於是要把這些二分圖組合起來,其中左部點和右部點是可以交換的。
那麼直接揹包就行了。

這裡的揹包可以用 bitset 最佳化,但是複雜度瓶頸不在這裡。

時間複雜度 \(\mathcal{O}(n^2)\)

#include<bits/stdc++.h>
inline int Cn2(int n) {return n * (n - 1) / 2;}
const int maxn = 7e2 + 10;
int n;
int G[maxn][maxn];
std::bitset<maxn * 2> f;
int col[maxn], vis[maxn];
bool dfs(int u, int &sum) {
   if (vis[u]++) return false;
   sum += col[u] ? 1 : -1;
   for (int v = 1; v <= n; v++)
      if (G[u][v]) {
         if (col[v] == -1) {
            col[v] = ! col[u];
            if (dfs(v, sum))
               return true;
         }
         if (col[u] == col[v])
            return true;
      }
   return false;
}
int main() {
   int m; scanf("%d%d", &n, &m);
   for (int x, y; m--; ) {
      scanf("%d%d", &x, &y);
      G[x][y] = G[y][x] = 1;
   }
   for (int i = 1; i <= n; i++)
      for (int j = 1; j <= n; j++)
         G[i][j] ^= i != j;
   memset(col, -1, sizeof(int) * (n + 1));
   f[maxn] = 1;
   for (int i = 1; i <= n; i++)
      if (col[i] == -1) {
         col[i] = 0;
         int sum = 0;
         if (dfs(i, sum))
            return puts("-1"), 0;
         sum = abs(sum);
         f = (f << sum) | (f >> sum);
      }
   for (int i = 0; i <= n; i++)
      if (f[maxn + i])
         return printf("%d\n", Cn2((n + i) / 2) + Cn2((n - i) / 2)), 0;
   return 0;
}

相關文章