URAL1627: Join 题解

把地图看成去掉障碍物的网格图,就可以用矩阵树定理直接算生成树个数了
矩阵树定理:
一个无向图的度数矩阵: d i , j = d e g i 当且仅当 i = j
一个无向图的邻接矩阵: A i , j = 1 当且仅当从 i j 有边
一个无向图的基尔霍夫矩阵: K i , j = d i , j A i , j
矩阵树定理:一个无向图的生成树个数等于其基尔霍夫矩阵的任意一个 n 1 阶主子式的行列式
所以只要高斯消元一发就好了
PS: 学到一个高斯消元技巧:通过辗转相除的方法避免高精度和double

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=1e9;
const LL LINF=2e16;
const int INF=2e9;
const int magic=348;
const double eps=1e-10;
const double pi=3.14159265;

inline int getint()
{
    char ch;int res;bool f;
    while (!isdigit(ch=getchar()) && ch!='-') {}
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
    while (isdigit(ch=getchar())) res=res*10+ch-'0';
    return f?res:-res;
}

int n,m;
char s[48][48];
int deg[148][148],ga[148][148];
int Ind[48][48],itot=0;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
LL a[148][148];

inline void doit(int i,int j)
{
    int ind=Ind[i][j];deg[ind][ind]=0;int xx,yy,dir;
    for (dir=0;dir<=3;dir++)
    {
        xx=i+dx[dir];yy=j+dy[dir];
        if (1<=xx && xx<=n && 1<=yy && yy<=m && Ind[xx][yy]) deg[ind][ind]++,ga[ind][Ind[xx][yy]]=1;
    }
}

inline LL mod(LL x) {while (x>=MOD) x-=MOD;while (x<0) x+=MOD;return x;}

inline LL calc_det()
{
    int i,j,k,x,y,fl=1;LL ans=1;
    for (i=1;i<=itot-1;i++)
    {
        for (j=i+1;j<=itot-1;j++)
        {
            x=i;y=j;
            while (a[y][i])
            {
                LL t=a[x][i]/a[y][i];
                for (k=i;k<=itot-1;k++)
                    a[x][k]=mod(a[x][k]-(a[y][k]*t)%MOD);
                swap(x,y);
            }
            if (x!=i)
            {
                for (k=i;k<=itot-1;k++) swap(a[x][k],a[y][k]);
                fl=-fl;
            }
        }
        if (a[i][i]==0) return 0;
        ans=(ans*a[i][i])%MOD;
    }
    if (fl==-1) ans=-ans;
    ans=mod(ans);
    return ans;
}

int main ()
{
    int i,j;n=getint();m=getint();
    for (i=1;i<=n;i++) scanf("%s",s[i]+1);
    for (i=1;i<=n;i++)
        for (j=1;j<=m;j++)
            if (s[i][j]=='.') Ind[i][j]=++itot;
    for (i=1;i<=n;i++)
        for (j=1;j<=m;j++)
            doit(i,j);
    for (i=1;i<=itot;i++)
        for (j=1;j<=itot;j++)
            a[i][j]=deg[i][j]-ga[i][j];
    printf("%lld\n",calc_det());
    return 0;
}

这题放在dp专题里,于是想用插头dp做
显然是轮廓线dp,有m+1个位置可能有插头,问题在于要维护插头的连通性,否则会得到不是树的东西
这里我们可以使用最小表示法
即对于每个位置,如果没有插头就是0,否则是与这个位置相连的最小插头的标号
这样相同标号的两个插头不能合并,否则形成环
然后注意什么样的插头可以在中间停止:即如果与这个插头相连的还有其他插头,或者这个格子已经是右下角就可以结束,否则会形成森林

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=1e9;
const LL LINF=2e16;
const int INF=2e9;
const int magic=348;
const double eps=1e-10;
const double pi=3.14159265;

inline int getint()
{
    char ch;int res;bool f;
    while (!isdigit(ch=getchar()) && ch!='-') {}
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
    while (isdigit(ch=getchar())) res=res*10+ch-'0';
    return f?res:-res;
}

int n,m;
char s[48][48];

inline int mod(int x) {while (x>=MOD) x-=MOD;while (x<0) x+=MOD;return x;}

const int p=199991;
struct Hash
{
    int head[200048],nxt[180048],val[180048],tot=1;LL to[180048];
    inline void clear()
    {
        memset(head,0,sizeof(head));
        tot=1;
    }
    inline void Insert(LL x,int add)
    {
        LL pos=x%p;int i;LL y;bool f=false;
        for (i=head[pos];i;i=nxt[i])
        {
            y=to[i];
            if (y==x) {val[i]=mod(val[i]+add);f=true;break;}
        }
        if (!f) {to[++tot]=x;nxt[tot]=head[pos];head[pos]=tot;val[tot]=add;}
    }
}hsh[2];

inline int getplug(LL Mask,int pos) {return (Mask>>((pos-1)*4))&15ll;}
inline LL setplug(LL Mask,int pos,LL plug) {Mask|=(15ll<<((pos-1)*4));Mask^=(plug<<((pos-1)*4));Mask^=(15ll<<((pos-1)*4));return Mask;}
inline LL modify(LL Mask,int p1,int p2)
{
    for (register int i=1;i<=m+1;i++)
        if (getplug(Mask,i)==p2) Mask=setplug(Mask,i,p1);
    return Mask;
}

int lx,ly;
inline bool check(int i,int j,LL Mask,int plug)
{
    if (i==lx && j==ly) return true;int cnt=0;
    for (register int i=1;i<=m+1;i++)
        if (getplug(Mask,i)==plug) cnt++;
    return cnt;
}

inline LL getMask(LL Mask)
{
    int i,ind=0,table[48],plug;LL res=0;
    memset(table,0,sizeof(table));
    res=Mask;
    for (i=1;i<=m+1;i++)
    {
        plug=getplug(Mask,i);
        if (plug)
        {
            if (!table[plug]) table[plug]=++ind;
            res=setplug(res,i,table[plug]);
        }
    }
    return res;
}

int main ()
{
    int i,j,k,r;n=getint();m=getint();
    for (i=1;i<=n;i++) scanf("%s",s[i]+1);
    hsh[0].clear();hsh[1].clear();hsh[0].Insert(0,1);
    int cur=0,nxt=1;LL Mask,toMask;int p1,p2,bel;
    int ans=0;
    lx=n;ly=m;
    while (s[lx][ly]=='*')
    {
        ly--;
        if (ly==0)
        {
            lx--;
            ly=m;
        }
        if (lx==0) break;
    }
    if (lx==0) {puts("0");return 0;}
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=m;j++)
        {
            for (r=0;r<=p-1;r++)
                for (k=hsh[cur].head[r];k;k=hsh[cur].nxt[k])
                {
                    Mask=hsh[cur].to[k];
                    p1=getplug(Mask,j);p2=getplug(Mask,j+1);
                    if (s[i][j]=='.')
                    {
                        if (p1 && p2)
                        {
                            if (p1==p2) continue;
                            bel=min(p1,p2);Mask=modify(Mask,bel,max(p1,p2));
                        }
                        if (!p1 && !p2) bel=15;
                        if ((p1 && !p2) || (!p1 && p2)) bel=max(p1,p2);
                        Mask=setplug(Mask,j,0);Mask=setplug(Mask,j+1,0);
                        if (check(i,j,Mask,bel))
                        {
                            toMask=Mask;toMask=setplug(toMask,j,0);toMask=setplug(toMask,j+1,0);
                            toMask=getMask(toMask);
                            hsh[nxt].Insert(toMask,hsh[cur].val[k]);
                        }
                        if (i!=n)
                        {
                            toMask=Mask;toMask=setplug(toMask,j,bel);toMask=setplug(toMask,j+1,0);
                            toMask=getMask(toMask);
                            hsh[nxt].Insert(toMask,hsh[cur].val[k]);
                        }
                        if (j!=m)
                        {
                            toMask=Mask;toMask=setplug(toMask,j+1,bel);toMask=setplug(toMask,j,0);
                            toMask=getMask(toMask);
                            hsh[nxt].Insert(toMask,hsh[cur].val[k]);
                        }
                        if (i!=n && j!=m)
                        {
                            toMask=Mask;toMask=setplug(toMask,j,bel);toMask=setplug(toMask,j+1,bel);
                            toMask=getMask(toMask);
                            hsh[nxt].Insert(toMask,hsh[cur].val[k]);
                        }
                    }
                    else
                    {
                        if (p1 || p2) continue;
                        hsh[nxt].Insert(Mask,hsh[cur].val[k]);
                    }   
                }
            swap(cur,nxt);hsh[nxt].clear();
        }
        if (i!=n)
        {
            for (r=0;r<=p-1;r++)
                for (k=hsh[cur].head[r];k;k=hsh[cur].nxt[k])
                {
                    Mask=hsh[cur].to[k];
                    Mask=Mask<<4;Mask=setplug(Mask,1,0);
                    hsh[nxt].Insert(Mask,hsh[cur].val[k]);
                }
            swap(cur,nxt);hsh[nxt].clear();
        }
    }
    for (k=hsh[cur].head[0];k;k=hsh[cur].nxt[k])
        if (hsh[cur].to[k]==0) {printf("%d\n",hsh[cur].val[k]);return 0;}
    printf("0\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/IcePrincess_1968/article/details/80780663
今日推荐