题解 彩色挂饰

传送门

发现一个星座就是一个点双
发现每个点双大小只有 6
发现对每个点双 \(k^{|s|}\) 枚举染色理论上有 60~80 pts
最后发现自己已经不会写圆方树了回归 20 pts

正解基本上就是这个东西
发现大力枚举染色很无脑
将具体式子写出来发现贡献和每个点双内部的同色连通块数有关
那么大力状压一下,每次枚举子集加入一个同色连通块即可
复杂度 \(O(n(3^s+2^sk))\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, k, s;
pair<int, int> g[N*12];
int head[N], c[N], deg[N], ecnt;
struct edge{int to, next;}e[N*12];
inline void add(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}

namespace force{
	int col[N], dsu[N], ans=INF;
	inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
	void calc() {
		for (int i=1; i<=n; ++i) dsu[i]=i;
		for (int u=1; u<=n; ++u) {
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (col[u]==col[v]) dsu[find(u)]=find(v);
			}
		}
		int cnt=0;
		for (int i=1; i<=n; ++i) if (find(i)==i) ++cnt;
		ans=min(ans, cnt);
	}
	void dfs(int u) {
		if (u>n) {calc(); return ;}
		if (c[u]) {col[u]=c[u]; dfs(u+1);}
		else for (int i=1; i<=k; ++i) col[u]=i, dfs(u+1);
	}
	void solve() {
		dfs(1);
		cout<<ans<<endl;
	}
}

namespace task1{
	int f[N][21], g[N];
	void dfs(int u, int fa) {
		for (int i=head[u],v; ~i; i=e[i].next) if (e[i].to!=fa) dfs(e[i].to, u);
		for (int col=1; col<=k; ++col) if (!c[u]||c[u]==col) {
			int sum=0;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (v==fa) continue;
				sum+=min(g[v]+1, f[v][col]);
			}
			f[u][col]=sum;
		}
		for (int i=1; i<=k; ++i) g[u]=min(g[u], f[u][i]);
	}
	void solve() {
		memset(f, 0x3f, sizeof(f));
		memset(g, 0x3f, sizeof(g));
		dfs(1, 0);
		cout<<g[1]+1<<endl;
	}
}

namespace task{
	bool cut[N], link[1<<6];
	vector<int> dcc[N], to[N];
	ll f[N][21], g[1<<6][21], G[1<<6], h[1<<6], ans=INF;
	int dfn[N], low[N], sta[N], bel[N], id[N], out[N], top, tot, cnt, rot;
	void tarjan(int u) {
		dfn[u]=low[u]=++tot;
		sta[++top]=u;
		bool flag=0;
		if (u==rot&&head[u]==-1) dcc[++cnt].pb(u);
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (!dfn[v]) {
				tarjan(v);
				low[u]=min(low[u], low[v]);
				if (u!=rot||flag) cut[u]=1;
				else flag=1;
				if (dfn[u]<=low[v]) {
					++cnt;
					do {
						to[cnt].pb(sta[top]);
						dcc[cnt].pb(sta[top--]);
					} while (sta[top+1]!=v);
					dcc[cnt].pb(u);
					to[u].pb(cnt);
				}
			}
			else low[u]=min(low[u], dfn[v]);
		}
	}
	void dfs(int u, int fa) {
		for (auto v:to[u]) dfs(v, u);
		if (u<=n) {
			for (int i=1; i<=k; ++i) if (!c[u]||c[u]==i) {
				f[u][i]=1;
				for (auto v:to[u]) f[u][i]+=f[v][i]-1;
			}
		}
		else {
			for (int i=0; i<dcc[u].size(); ++i) id[dcc[u][i]]=i;
			int siz=dcc[u].size(), lim=1<<siz;
			for (int s=0; s<lim; ++s) link[s]=0;
			for (int i=0; i<siz; ++i) link[1<<i]=1;
			for (auto it:dcc[u]) bel[it]=u;
			for (auto it:dcc[u]) {
				out[id[it]]=0;
				for (int i=head[it]; ~i; i=e[i].next) if (bel[e[i].to]==u) out[id[it]]|=1<<id[e[i].to];
				// cout<<out[id[it]]<<endl;
			}
			for (int s=1; s<lim; ++s) if (__builtin_popcount(s)>1)
				for (int i=0; i<siz&&!link[s]; ++i) if (s&(1<<i)) link[s]|=link[s^(1<<i)]&&(out[i]&s);
			// cout<<"link: "; for (int s=0; s<lim; ++s) cout<<link[s]; cout<<endl;
			for (int s=0; s<lim; ++s) {
				G[s]=INF;
				for (int i=1; i<=k; ++i) {
					if (!link[s]) g[s][i]=INF;
					else {
						g[s][i]=1;
						for (int j=0; j<siz; ++j) if ((s&(1<<j)) && dcc[u][j]!=fa) g[s][i]+=f[dcc[u][j]][i]-1;
					}
					G[s]=min(G[s], g[s][i]);
				}
			}
			// cout<<"G: "; for (int s=0; s<lim; ++s) cout<<G[s]<<' '; cout<<endl;
			h[0]=0;
			for (int s=1; s<lim; ++s) {
				h[s]=INF;
				for (int t=s; t; t=(t-1)&s) if (link[t])
					h[s]=min(h[s], h[s^t]+G[t]);
			}
			for (int i=1; i<=k; ++i)
				for (int s=0; s<lim; ++s) if (s&(1<<id[fa]))
					f[u][i]=min(f[u][i], g[s][i]+h[(lim-1)^s]);
		}
	}
	void solve() {
		cnt=n; rot=1; tarjan(1);
		for (int i=1; i<=cnt; ++i) for (int j=1; j<=k; ++j) f[i][j]=INF;
		// cout<<"id : "; for (int i=1; i<=n; ++i) cout<<i<<' '; cout<<endl;
		// cout<<"bel: "; for (int i=1; i<=n; ++i) cout<<bel[i]<<' '; cout<<endl;
		// cout<<"cut: "; for (int i=1; i<=n; ++i) cout<<cut[i]<<' '; cout<<endl;
		// cout<<"---dcc---"<<endl; for (int i=n+1; i<=cnt; ++i) {for (auto it:dcc[i]) cout<<it<<' '; cout<<endl;}
		dfs(1, 0);
		// cout<<"---f---"<<endl; for (int i=1; i<=cnt; ++i) {for (int j=1; j<=k; ++j) cout<<f[i][j]<<' '; cout<<endl;}
		for (int i=1; i<=k; ++i) ans=min(ans, f[1][i]);
		cout<<ans<<endl;
	}
}

signed main()
{
	freopen("colorful.in", "r", stdin);
	freopen("colorful.out", "w", stdout);

	n=read(); m=read(); k=read(); s=read();
	memset(head, -1, sizeof(head));
	for (int i=1; i<=n; ++i) c[i]=read();
	for (int i=1,u,v; i<=m; ++i) {
		u=read(); v=read();
		add(u, v); add(v, u);
		++deg[u], ++deg[v];
		g[i]={u, v};
	}
	// if (n<=20) force::solve();
	// else task1::solve();
	task::solve();

	return 0;
}
posted @ 2022-05-16 21:56  Administrator-09  阅读(2)  评论(0编辑  收藏  举报