Bzoj1016: [JSOI2008]最小生成樹計數
阿新 • • 發佈:2018-02-27
puts fill 組成 ret bzoj https ++ unique tor
題面
傳送門
Sol
最小生成樹的性質:
- 對於每一個\(MST\),每一種邊權所使用的邊數相同
- 所有\(MST\)中邊權\(≤w\)的邊組成的圖的連通性相同
那麽這道題就枚舉沒個權值選那些邊,如果連的個數和原來的相同就統計
最後乘法原理即可
如果同邊權過多就只能用矩陣樹定理了
然而我太菜了不會。。
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
# define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
using namespace std;
typedef long long ll;
const int Zsy(31011);
const int _(105);
const int __(1005);
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9' ; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int n, m, fa[_], ans = 1, o[__], len, l[__], r[__], id[__], cnt[__], tmp[_];
struct Edge{
int u, v, w;
IL bool operator <(RG Edge B) const{
return w < B.w;
}
} edge[__];
IL int Find(RG int x){
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
IL int Count(RG int x){
RG int ret = 0;
for(; x; x -= x & -x) ++ret;
return ret;
}
int main(RG int argc, RG char* argv[]){
n = Input(), m = Input();
for(RG int i = 1; i <= n; ++i) fa[i] = i;
for(RG int i = 1; i <= m; ++i){
edge[i] = (Edge){Input(), Input(), Input()};
o[i] = edge[i].w, l[i] = m, r[i] = 1;
}
sort(edge + 1, edge + m + 1);
sort(o + 1, o + m + 1), len = unique(o + 1, o + m + 1) - o - 1;
RG int gg = 0;
for(RG int i = 1; i <= m; ++i){
RG int fx = Find(edge[i].u), fy = Find(edge[i].v);
id[i] = lower_bound(o + 1, o + len + 1, edge[i].w) - o;
l[id[i]] = min(l[id[i]], i), r[id[i]] = max(r[id[i]], i);
if(Find(fx) == Find(fy)) continue;
fa[fx] = fy, ++cnt[id[i]], ++gg;
}
if(gg != n - 1) return puts("0"), 0;
for(RG int i = 1; i <= n; ++i) fa[i] = i;
for(RG int i = 1; i <= len; ++i){
RG int tot = 0;
for(RG int j = 1; j <= n; ++j) tmp[j] = fa[j];
for(RG int j = 0, S = 1 << (r[i] - l[i] + 1); j < S; ++j){
if(Count(j) != cnt[i]) continue;
RG int flg = 0;
for(RG int k = 1; k <= n; ++k) fa[k] = tmp[k];
for(RG int k = 0; k <= r[i] - l[i]; ++k)
if((1 << k) & j){
RG int fx = Find(edge[k + l[i]].u), fy = Find(edge[k + l[i]].v);
if(fx == fy){
flg = 1;
break;
}
fa[fx] = fy;
}
if(!flg) ++tot;
}
ans = ans * tot % Zsy;
for(RG int j = 1; j <= n; ++j) fa[j] = tmp[j];
for(RG int j = l[i]; j <= r[i]; ++j){
RG int fx = Find(edge[j].u), fy = Find(edge[j].v);
if(fx != fy) fa[fx] = fy;
}
}
printf("%d\n", ans);
return 0;
}
Bzoj1016: [JSOI2008]最小生成樹計數