題意
給你一個圖,每條邊有一個邊權。
現在你可以對每條邊染色,染成黑色或白色。
一種合法的染色方案指的是染色完畢後,對原圖求MST(最小生成樹)。最小生成樹滿足所有樹上的邊至少包含一條黑色變和白色邊。然後最小生成樹的邊權和要等於給出的X值。
求合法染色方案數。
思考歷程
開始沒什麼想法。
然後我假設sum爲求一遍MST的值。
發現我們可以對x分成三種情況,一種是,顯然沒有情況。
一種是,這種情況推了老半天,推出來的似乎還錯了。
另外一種是,這個還是有個瓶頸。大致求出那些邊放進去後sum可以變成x。
然鵝其他影響的邊我就想不到了。
好蔡啊。
題解
看完題解就懂了。
其實再求一個表示當前邊放入生成樹後對答案的影響即可。
然後我就發現我全會了。
值其實可以求,打個LCA即可。然鵝數據很水,暴力也可以。
的情況就是求出MST後,設表示值爲0的邊的個數。
然後答案即爲:
左邊:首先這些邊可以隨便染色,因爲無論怎麼組合它們組成的MST都是等於X的,減2表示這些邊不能全部染成黑色或白色。
右邊:無關的邊就隨便染色了。
的情況是我們要求出最小生成樹後,把每條邊染成同種顏色,然後再斷掉其中某條邊,連一條更大的邊。
先求出三個東東:設分別表示
那麼我們發現,的邊必須都是和生成樹的邊的顏色相同,否則生成樹必選這些邊。
的邊就可以隨便搞,但是要注意不能全部的這些邊都染成和生成樹一樣的顏色。
的邊就是無關邊,隨意搞。
答案即爲:
標程
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const long long mo=1000000007;
const int maxn=200010;
int n,m,x[maxn],y[maxn],f[maxn];
int fa[maxn],dep[maxn];
int tot,nex[maxn*2],las[maxn*2],tov[maxn*2];
bool bz[maxn];
long long ans,X,sum,v[maxn],z[maxn],val[maxn*2];
void insert(int x,int y,long long z)
{
tot++;
tov[tot]=y;
nex[tot]=las[x];
las[x]=tot;
val[tot]=z;
}
void qsort(int l,int r)
{
int i=l;int j=r;
int m=z[(i+j)/2];
while (i<=j)
{
while (z[i]<m) i++;
while (z[j]>m) j--;
if (i<=j)
{
swap(x[i],x[j]);
swap(y[i],y[j]);
swap(z[i],z[j]);
i++;j--;
}
}
if (l<j) qsort(l,j);
if (r>i) qsort(i,r);
}
int getfather(int x)
{
if (f[x]==x) return x;
f[x]=getfather(f[x]);
return f[x];
}
long long qsm(long long a,long long b)
{
long long t=1;
long long y=a;
while (b>0)
{
if ((b&1)==1) t=t*y%mo;
y=y*y%mo;
b/=2;
}
return t;
}
void dfs(int x,int ff)
{
fa[x]=ff;
dep[x]=dep[ff]+1;
for (int i=las[x];i;i=nex[i])
{
if (tov[i]!=ff)
{
dfs(tov[i],x);
v[tov[i]]=val[i];
}
}
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%lld",&X);
for (int i=1;i<=m;i++)
{
scanf("%d%d%lld",&x[i],&y[i],&z[i]);
}
for (int i=1;i<=n;i++) f[i]=i;
qsort(1,m);
for (int i=1;i<=m;i++)
{
int xx=getfather(x[i]);
int yy=getfather(y[i]);
if (xx!=yy)
{
f[xx]=yy;
bz[i]=true;
sum+=z[i];
insert(x[i],y[i],z[i]);
insert(y[i],x[i],z[i]);
}
}
dfs(1,0);
for (int i=1;i<=m;i++)
{
if (!bz[i])
{
int xx=x[i];
int yy=y[i];
long long zd=0;
while (xx!=yy)
{
if (dep[xx]>dep[yy])
{
zd=max(zd,v[xx]);
xx=fa[xx];
}
else
{
zd=max(zd,v[yy]);
yy=fa[yy];
}
}
z[i]=z[i]-zd;
}
}
if (sum>X)
{
printf("0\n");
}
else
if (sum==X)
{
long long gs=0;
for (int i=1;i<=m;i++)
{
if (!bz[i])
{
if (z[i]==0) gs++;
}
}
ans=(qsm(2,gs+n-1)-2+mo)%mo;
ans=ans*qsm(2,m-gs-n+1)%mo;
// ans=(ans+(2*(qsm(2,gs)-1)%mo)%mo)%mo;
// printf("%0\n");
printf("%lld\n",ans);
}
else
{
long long op=X-sum;
long long gsa=0;long long gsb=0;long long gsc=0;
for (int i=1;i<=m;i++)
{
if (!bz[i])
{
if (z[i]<op)
{
gsa++;
}
else
if (z[i]==op)
{
gsb++;
}
else
{
gsc++;
}
}
}
if (gsb==0)
{
printf("0\n");
return 0;
}
else
{
ans=2;
ans=ans*((qsm(2,gsb)-1+mo)%mo)%mo;
ans=ans*qsm(2,gsc)%mo;
printf("%lld\n",ans);
}
}
}