Po姐说:http://blog.youkuaiyun.com/PoPoQQQ/article/details/46830025
仙人掌hash
现在变成了仙人掌,那么我把每个环变成一个红点连向环上的所有点,然后把原先环上的边拆除,可以得到一棵树,按树同构做就行了
为了区分红点和普通点的区别,需要为红点设置不同的哈希参数
但是这样有一个BUG,就是原先环上的点是有顺序的,而变成树之后也需要有序
因此对于一个红点,如果它不是树的根节点,计算贡献的时候判断将环翻转是否与原来相同即可
Hash的时候正反Hash两遍,取最小值
不过他的做法没仔细看诶
看的是这个:http://trinklee.blog.163.com/blog/static/238158060201552051143521
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
#define P 1000000003LL
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=1005;
const int M=10005;
int n,m;
ll fac[N],f[N],ans;
ull hash[N],sx[N],num1,loop[N];
struct edge{
int u,v,next;
};
edge G[M]; int flag[M];
int head[N],inum=1;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int fat[N],vst[N];
int cnt,cir[N],size[N];
int first[N],next[N];
inline void cdd(int x,int u){
size[x]++; cir[u]=x; next[u]=first[x]; first[x]=u;
}
#define V G[p].v
void dfs(int u){
vst[u]=1;
for (int p=head[u];p;p=G[p].next)
if (!flag[p] && !cir[V])
{
flag[p]=flag[p^1]=1;
if (vst[V])
{
cdd(++cnt,V);
for(int i=u;i!=V;i=fat[i]) cdd(cnt,i);
}
else
fat[V]=u,dfs(V);
flag[p]=flag[p^1]=0;
}
}
#define nxt(x) ((x)==m?1:(x)+1)
#define pev(x) ((x)==1?m:(x)-1)
void calc(int u,int d){
f[u]=1; hash[u]=1;
for (int p=head[u];p;p=G[p].next)
if (!flag[p] && cir[V]!=cir[u]){
flag[p]=flag[p^1]=1;
calc(V,d+1);
(f[u]*=f[V])%=P;
flag[p]=flag[p^1]=0;
}
int m=0,sm=1,mid;
if(vst[cir[u]]!=2 && size[cir[u]]!=1){
vst[cir[u]]=2;
for (int i=first[cir[u]];i;i=next[i])
if (i!=u)
calc(i,d+1),(f[u]*=f[i])%=P;
for (int i=first[cir[u]];i;i=next[i])
{
loop[++m]=hash[i];
if (i==u) mid=m;
}
for(int i=pev(mid),j=nxt(mid),t=1;t<=m/2;i=pev(i),j=nxt(j),t++)
if (loop[i]!=loop[j])
sm=0;
if(sm && size[cir[u]]!=2) (f[u]*=2)%=P;
vst[cir[u]]=0;
}
int t=0,j=1;
for (int p=head[u];p;p=G[p].next)
if (!flag[p] && cir[u]!=cir[V])
sx[++t]=hash[V];
sort(sx+1,sx+t+1);
for(int i=2;i<=t;i++)
if(sx[i]==sx[i-1])
j++;
else
(f[u]*=fac[j])%=P,j=1;
(f[u]*=fac[j])%=P;
for (int i=1;i<=m;i++)
if (i!=mid)
{
int s=abs(i-mid);
s=min(s,m-s);
sx[++t]=loop[i]*(233+size[cir[u]])+s;
}
sort(sx+1,sx+t+1);
for (int i=1;i<=t;i++)
hash[u]=hash[u]*131+sx[i];
hash[u]*=d;
}
int main()
{
int iu,iv,icnt=1;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(m);
fac[0]=1; for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;
for (int i=1;i<=m;i++)
read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);
dfs(1);
for(int i=1;i<=n;i++)
if (!cir[i])
cir[i]=++cnt,size[cnt]=1;
calc(1,1);
ans=f[1]; num1=hash[1];
for(int i=2;i<=n;i++){
cl(hash); cl(f);
calc(i,1);
if (num1==hash[i])
icnt++;
}
printf("%lld\n",ans*icnt%P);
return 0;
}