bzoj3659 Which dreamed it

题目描述:

n个房间,每个房间有若干把钥匙能够打开特定房间的门。

你会做这么件事情:

最初你在房间1。

每当你到达一个房间,你可以选择该房间的一把钥匙,前往该钥匙对应的房间,并将该钥匙丢到垃圾桶中。

你希望:最终回到房间1,且垃圾桶中有所有的钥匙。

求方案数。两组方案不同,当且仅当使用钥匙的顺序不同。注意,每把钥匙都是不同的。

题解:

有个东西叫$BEST$定理。意思是一个有向图的欧拉回路数为生成数个数*$\prod^{n}_{i=1}(deg[i]-1)!$。

里面那个$deg$是入度或出度,反正一定相等。

由于本题要求边序不同即可,所以答案要多乘一个$deg[1]$。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 105;
const int MOD = 1000003;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,ind[N],otd[N],a[N][N];
bool check()
{
    for(int i=1;i<=n;i++)
        if(ind[i]!=otd[i])return 0;
    return 1;
}
ll fastpow(ll x,int y)
{
    ll ret = 1ll;
    while(y)
    {
        if(y&1)ret=ret*x%MOD;
        x=x*x%MOD;
        y>>=1;
    }
    return ret;
}
ll ma_tr()
{
    for(int i=1;i<n;i++)
        for(int j=1;j<n;j++)
            a[i][j]=(a[i][j]%MOD+MOD)%MOD;
    ll ret = ind[1];
/*    for(int i=1;i<n;i++)
        for(int j=i+1;j<n;j++)
            while(a[j][i])
            {
                ll d = a[i][i]/a[j][i];
                if(d)for(int k=i;k<n;k++)
                a[i][k]=(a[i][k]-d*a[j][k]%MOD+MOD)%MOD;
                swap(a[i],a[j]);ret=-ret;
            }*/
    for(int i=1;i<n;i++)
        for(int j=i+1;j<n;j++)
            while(a[j][i])
            {
                ll t = a[i][i]/a[j][i];
                if(t)for(int k=i;k<n;k++)
                a[i][k]=(a[i][k]-t*a[j][k]%MOD+MOD)%MOD;
                swap(a[i],a[j]);ret=-ret;
            }
    for(int i=1;i<n;i++)
        ret=(ret*a[i][i]%MOD+MOD)%MOD;
    return ret;
}
int main()
{
    while(1)
    {
        read(n);
        if(!n)break;
        memset(a,0,sizeof(a));
        memset(ind,0,sizeof(ind));
        memset(otd,0,sizeof(otd));
        for(int i=1;i<=n;i++)
        {
            read(otd[i]);a[i][i]=otd[i];
            for(int j=1,x;j<=otd[i];j++)
            {
                read(x);
                ind[x]++;
                a[i][x]--;
            }
        }
        if(!check()){puts("0");continue;}
        ll ans = ma_tr();
        for(int i=1;i<=n;i++)
            for(int j=1;j<ind[i];j++)
                ans=ans*j%MOD;
        printf("%lld\n",ans%MOD);
    }
    return 0;
}

 

posted @ 2019-02-16 09:22  LiGuanlin  阅读(149)  评论(0编辑  收藏  举报