【题解】P8315 [COCI 20212022 #4] Šarenlist
P8315 [COCI 20212022 #4] Šarenlist
题意
给定一棵树,\(n\) 个节点,给定了 \(m\) 条路径的起点和终点,有 \(k\) 种颜色,现在要给每条边染上一种颜色。
求有多少种染色方式,使得对于每条给定的条路径,都满足路径上至少有两种颜色。
答案对 \(10^9+7\) 取模。
\(n\le 60\),\(m\le 15\)。
题解
知识点:二项式反演,组合数学,容斥原理。
启发:
- 正难则反。
到了树上。
设 \(g_k\) 为恰好有 \(k\) 条路径不满足条件的方案数。
设 \(f_k\) 为钦定 \(k\) 条路径使得不满足条件,未涉及的边随便染色的方案数。
有如下关系,
\[\large \displaystyle f_k=\sum_{i=k}^m \binom{i}{k}\times g_i
\]
二项式反演,
\[\large \displaystyle g_k=\sum_{i=k}^m \binom{i}{k}\times (-1)^{i-k} f_i
\]
注意到 \(m\le 15\),这暗示可以 \(O(2^m)\) 枚举每一条路径的是否不满足。
先与处理出每一条路径包含的边的编号,存起来。
设当前状态为 \(s\),将 \(s\) 中为 \(1\) 的位对应的路径取出,在并查集上,依次将每一条路径中的边合并到同一连通块,当两条路径有边交集时,他们都合并到同一连通块。
要让选出来都路径都不合法,则在同一连通块的边得染上同一种颜色,设一共 \(c\) 个连通块,则染色方案为 \(k^c\),累加到 \(f_{\operatorname{popcount(s)}}\)。
答案即为 \(g_0\),此时 \(\displaystyle g_0=\sum_{i=0}^m (-1)^{i} f_i\),退化为了一般的容斥原理。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 66
#define int long long
const int mod=1e9+7;
int n,m,k,F[N];
bitset<N>f;
pr a[N],pre[N];
vector<pr>e[N];
vector<int>p[N];
inline int qpow(int a,int b){
int ans=1;
while(b){
if(b&1){
ans=ans*a%mod;
}
a=a*a%mod;
b>>=1;
}
return ans;
}
inline void dfs(int k){
f[k]=1;
for(pr x:e[k]){
if(f[x.fi]){
continue;
}
pre[x.fi]={k,x.se};
dfs(x.fi);
}
}
struct dsu{
int fa[N];
inline void init(){
rep(i,1,n){
fa[i]=i;
}
}
inline int ask(int k){
if(fa[k]==k){
return k;
}
return ask(fa[k]);
}
inline bool mg(int x,int y){
x=ask(x),y=ask(y);
if(x==y){
return 0;
}
fa[x]=y;
return 1;
}
}d;
inline void sol(int s){
vector<int>v;
rep(i,1,m){
if((s>>(i-1))&1){
v.pb(i);
}
}
d.init();
for(int x:v){
int len=sz(p[x]);
rep(i,1,len-1){
d.mg(p[x][i],p[x][i-1]);
}
}
int ans=1;
rep(i,1,n-1){
if(d.fa[i]==i){
ans=ans*k%mod;
}
}
F[sz(v)]=(F[sz(v)]+ans)%mod;
}
inline int neg(int x){
return x&1?-1:1;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m>>k;
rep(i,1,n-1){
int u,v;
cin>>u>>v;
e[u].pb({v,i});
e[v].pb({u,i});
}
rep(i,1,m){
cin>>a[i].fi>>a[i].se;
rep(j,1,n){
f[j]=0;
pre[j]={0,0};
}
dfs(a[i].fi);
int u=a[i].se;
while(pre[u].se){
p[i].pb(pre[u].se);
u=pre[u].fi;
}
}
rep(s,0,(1<<m)-1){
sol(s);
}
int ans=0;
rep(i,0,m){
ans=(ans+
neg(i)*F[i]
+mod
)%mod;
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号