1. 程式人生 > 其它 >題解 【UR #21】挑戰最大團

題解 【UR #21】挑戰最大團

link

Solution

我們可以知道以下一些性質:

  1. 優美的圖任意匯出子圖都是優美的

  2. 優美的圖的補圖也是優美的

  3. 優美的圖與其補題最多一個聯通

  4. 優美的圖直徑 \(\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;
}