您的位置:首页 > 其它

[bzoj]4596: [Shoi2016]黑暗前的幻想乡

2017-06-14 09:05 375 查看
此题用容斥做,答案就是没有不选的-一个不选的+两个不选的-三个不选的……

2^n枚举出不选的,算方案使用矩阵树定理

#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#define ll long long
using namespace std;
const ll pp=1000000007;
struct node{
int u[400],v[400];
}ct[20];
ll ans;
int n,x,y,t,m[20];
ll a[20][20];
inline ll work()
{
register int i,j,k;
ll que=1,f=1;
for (i=1;i<n;i++)
for (j=1;j<n;j++)
{
a[i][j]+=pp;
a[i][j]%=pp;
}
for (i=1;i<n;i++)
{
for (j=i+1;j<n;j++)
{
ll x=a[i][i],y=a[j][i];
while (y)
{
ll z=x/y;
x%=y;
swap(x,y);
for (k=i;k<n;k++) a[i][k]=(a[i][k]-z*a[j][k]%pp+pp)%pp;
for (k=i;k<n;k++) swap(a[i][k],a[j][k]);
f=-f;
}
}
if (!a[i][i]) return 0;
(que*=a[i][i])%=pp;
}

return (que*f+pp)%pp;
}
int main()
{
register int i,j,k;
scanf("%d",&n);
for (i=1;i<=n-1;i++)
{
scanf("%d",&m[i]);
for (j=1;j<=m[i];j++) scanf("%d %d",&ct[i].u[j],&ct[i].v[j]);
}
for (i=1;i<(1<<(n-1));i++)
{
t=0;
memset(a,0,sizeof(a));
for (j=1;j<n;j++)
if (i&(1<<(j-1)))
{
t++;
for (k=1;k<=m[j];k++)
{
a[ct[j].u[k]][ct[j].v[k]]--;
a[ct[j].v[k]][ct[j].u[k]]--;
a[ct[j].u[k]][ct[j].u[k]]++;
a[ct[j].v[k]][ct[j].v[k]]++;
}
}
(ans+=work()*pow(-1,(n-1-t)&1)+pp)%=pp;
}
printf("%lld",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: