题解 彩色挂饰
发现一个星座就是一个点双
发现每个点双大小只有 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;
}