题意:给你一个仙人掌,然后把所有节点置换一下,求一共有多少置换满足置换后边不变。
Q:如何让代码变长?
A:将所有tab换成4个空格。
看到bz上我5k的代码我是懵逼的。。。
把一个环变成一个红点连环上的其他边。这步用一个栈维护一下dfs到当前点的所有祖先就行了。
然后变成了一棵树,那么用正常树hash就行了。
一个普通点,考虑他每种儿子的个数(hash值相同的算一种儿子),假设一种儿子有x个,那么答案乘
如果是一个红点:
如果这个红点不是根,那么只需要考虑这个环翻转后和原来是否一样,如果一样那么答案∗2
这个只需要正着做一遍hash,反着做一遍hash,然后看一不一样。
并且这个点的hash值取正反hash值的最小值。
如果这个红点是根,那么把所有儿子hash值连起来,把串倍长,分别用这个串和他的反串匹配。答案乘匹配个数。
注意普通点和红点需要用两个hash种子。
#include <bits/stdc++.h>
using namespace std;
#define N 2100
#define M 51000
#define mod 1000000003
#define seed1 233333333
#define seed2 2147483647
#define end1 20140355
#define end2 5462617
#define ll long long
#define ull unsigned long long
int n,m;
int jc[N];
struct cactus
{
int tot,n,f1,f2;
int head[N],nex[M],to[M],type[N];
int size[N],f[N],cnt[N];
ull has[N],son[N][N],ans;
void add(int x,int y)
{
tot++;
nex[tot]=head[x];head[x]=tot;
to[tot]=y;
}
void ade(int x,int y)
{add(x,y);add(y,x);}
void findroot(int x,int y)
{
size[x]=1;
for(int i=head[x];i;i=nex[i])
if(to[i]!=y)
{
findroot(to[i],x);
size[x]+=size[to[i]];
f[x]=max(f[x],size[to[i]]);
}
f[x]=max(f[x],n-size[x]);
if(f[x]<f[f1])f2=f1,f1=x;
else if(f[x]<f[f2])f2=x;
}
void del(int x,int y)
{
if(to[head[x]]==y)head[x]=nex[head[x]];
for(int i=head[x];i;i=nex[i])
if(to[nex[i]]==y)
{
nex[i]=nex[nex[i]];
break;
}
}
void dfs(int x,int y)
{
has[x]=type[x]+1;
for(int i=head[x];i;i=nex[i])
if(to[i]!=y)
{
dfs(to[i],x);
son[x][++cnt[x]]=has[to[i]];
}
if(type[x])
{
if(x==f1)
{
int sum=0;
for(int i=1;i<=cnt[x];i++)
son[x][cnt[x]+i]=son[x][i];
for(int i=1;i<=cnt[x];i++)
{
int flag=0;
for(int j=1;j<=cnt[x];j++)
if(son[x][j]!=son[x][i+j-1])
{flag=1;break;}
if(!flag)sum++;
}
for(int i=1;i<=cnt[x];i++)
{
int flag=0;
for(int j=1;j<=cnt[x];j++)
if(son[x][cnt[x]-j+1]!=son[x][i+j-1])
{flag=1;break;}
if(!flag)sum++;
}
ans=(ll)ans*sum%mod;
}
else
{
ull tmp=2;
for(int i=1;i<=cnt[x];i++)
has[x]=has[x]*seed2+son[x][i];
for(int i=cnt[x];i>=1;i--)
tmp=tmp*seed2+son[x][i];
if(tmp==has[x])ans=ans*2%mod;
has[x]=min(has[x],tmp);
(has[x]*=end2)^=end2;
}
}
else
{
sort(son[x]+1,son[x]+1+cnt[x]);
for(int i=1;i<=cnt[x];i++)
has[x]=has[x]*seed1+son[x][i];
for(int i=1,j;i<=cnt[x];i++)
{
j=i;
while(son[x][i]==son[x][j]&&j<=cnt[x])j++;j--;
ans=(ll)ans*jc[j-i+1]%mod;
i=j;
}
(has[x]*=end1)^=end1;
}
}
int solve()
{
f[0]=1<<30;ans=1;
for(int i=1;i<=n;i++)
if(!size[i])
{
f1=f2=0;
findroot(i,0);
if(f[f1]==f[f2])
{
del(f1,f2);del(f2,f1);
n++;size[n]=1;
ade(n,f1);ade(n,f2);
f1=n;
}
dfs(f1,0);
}
return ans;
}
}C;
struct init
{
int tot,top;
int head[N],nex[M],to[M];
int st[N],inc[N],vis[N],fa[N],deep[N];
void add(int x,int y)
{
tot++;
nex[tot]=head[x];head[x]=tot;
to[tot]=y;
}
void dfs(int x,int y)
{
vis[x]=1;fa[x]=y;
st[++top]=x;deep[x]=deep[y]+1;
for(int i=head[x];i;i=nex[i])
if(to[i]!=y)
{
if(!vis[to[i]])dfs(to[i],x);
else if(deep[to[i]]<deep[x])
{
int j;
for(j=top;st[j]!=to[i];j--);
C.n++;C.type[C.n]=1;
for(;j<=top;j++)
{
inc[st[j]]=1;
C.ade(st[j],C.n);
}
if(fa[to[i]])C.ade(to[i],fa[to[i]]);
}
}
top--;
if(!inc[x]&&y)C.ade(x,y);
}
}I;
int main()
{
//freopen("tt.in","r",stdin);
scanf("%d%d",&n,&m);
jc[0]=1;
for(int i=1;i<=n;i++)
jc[i]=(ll)jc[i-1]*i%mod;
for(int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
I.add(x,y);I.add(y,x);
}
C.n=n;
for(int i=1;i<=n;i++)
if(!I.vis[i])
I.dfs(i,0);
printf("%d\n",C.solve());
return 0;
}