題解 【UR #21】挑戰最大團
阿新 • • 發佈:2021-12-14
Solution
我們可以知道以下一些性質:
-
優美的圖任意匯出子圖都是優美的
-
優美的圖的補圖也是優美的
-
優美的圖與其補題最多一個聯通
-
優美的圖直徑 \(\le 2\)
那麼,我們求最大獨立集就可以用分治解決,注意需要使用啟發式分裂。
Code
#include <bits/stdc++.h> using namespace std; #define Int register int #define mod 998244353 #define MAXN 8005 template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;} template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);} template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> inline void chkmin (T &a,T b){a = min (a,b);} template <typename T> inline void chkmax (T &a,T b){a = max (a,b);} int getnum (char x){ if (x >= '0' && x <= '9') return x - '0'; return x - 'A' + 10; } bool mp[MAXN][MAXN]; int n,kas,deg[MAXN],vis[MAXN]; int mul (int a,int b){return 1ll * a * b % mod;} int dec (int a,int b){return a >= b ? a - b : a + mod - b;} int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;} void Add (int &a,int b){a = add (a,b);} void Sub (int &a,int b){a = dec (a,b);} void get_ans (vector <int> &a,int len,vector <int> &ans) ; int fuckit (vector <int> &a,int len,vector <int> &ans,int st,int op){ vis[st] = ++ kas; for (Int i = 1;i <= len;++ i) if (mp[st][a[i]] == (op ^ 1)){ vis[a[i]] = kas; for (Int j = 1;j <= len;++ j) if (mp[a[i]][a[j]] == (op ^ 1)) vis[a[j]] = kas; } bool flg = 0; for (Int i = 1;i <= len;++ i) if (vis[a[i]] != kas) flg = 1; if (!flg) return 0; vector <int> al,ar,ansl,ansr;int lenl = 0,lenr = 0; al.push_back (0),ar.push_back (0); for (Int i = 1;i <= len;++ i) if (vis[a[i]] == kas) al.push_back (a[i]),++ lenl;else ar.push_back (a[i]),++ lenr; ansl.resize (lenl + 1),ansr.resize (lenr + 1); for (Int i = 1;i <= lenl;++ i) for (Int j = 1;j <= lenr;++ j) if (mp[al[i]][ar[j]]) mp[al[i]][ar[j]] = 0,deg[al[i]] --,deg[ar[j]] --; for (Int i = 1;i <= lenl;++ i) ansl[i] = 0;for (Int i = 1;i <= lenr;++ i) ansr[i] = 0; get_ans (al,lenl,ansl),get_ans (ar,lenr,ansr); for (Int i = 1;i <= lenl;++ i) Add (ans[i],ansl[i]); for (Int i = 1;i <= lenr;++ i) Add (ans[i],ansr[i]); if (op == 0) ; else for (Int i = 1;i <= lenl;++ i) for (Int j = 1;j <= lenr;++ j) Add (ans[i + j],mul (ansl[i],ansr[j])); return 1; } #define pii pair<int,int> void get_ans (vector <int> &a,int len,vector <int> &ans){ if (len == 1){ ans[1] = 1; return ; } pii fuc[2];fuc[0].first = fuc[1].first = 1e9; for (Int i = 1;i <= len;++ i) chkmin (fuc[0],{deg[a[i]],a[i]}),chkmin (fuc[1],{len - deg[a[i]] - 1,a[i]}); int opt = (fuc[0].first > fuc[1].first); if (!fuckit (a,len,ans,fuc[opt].second,opt)) fuckit (a,len,ans,fuc[opt ^ 1].second,opt); } char s[MAXN]; signed main(){ read (n); for (Int i = 1;i < n;++ i){ scanf ("%s",s); for (Int j = 0;j < n - i;++ j) mp[i][i + j + 1] = mp[i + j + 1][i] = (getnum (s[j / 4]) >> (j & 3) & 1); } for (Int i = 1;i <= n;++ i) for (Int j = 1;j <= n;++ j) deg[i] += mp[i][j]; vector <int> sa,ans;sa.resize (n + 1),ans.resize (n + 1); for (Int i = 1;i <= n;++ i) sa[i] = i;get_ans (sa,n,ans); for (Int i = 1;i <= n;++ i) write (ans[i]),putchar (' ');putchar ('\n'); return 0; }