题目大意:给定一棵仙人掌,求有多少自同构
仙人掌同构问题= =
曾经出过一个判断两个仙人掌是否同构的题,感觉和这个题很类似
首先假设这是一棵树,考虑怎么做
我们首先找到树的重心(如果有两个就在中间加一个点变成一个)
然后把树Hash
对于一棵树 如果某一哈希值的子树有k个 就把答案乘上一个k!
现在变成了仙人掌,那么我把每个环变成一个红点连向环上的所有点,然后把原先环上的边拆除,可以得到一棵树,按树同构做就行了
为了区分红点和普通点的区别,需要为红点设置不同的哈希参数
但是这样有一个BUG,就是原先环上的点是有顺序的,而变成树之后也需要有序
因此对于一个红点,如果它不是树的根节点,计算贡献的时候判断将环翻转是否与原来相同即可
Hash的时候正反Hash两遍,取最小值
如果它是树的根节点,问题就变为了给定一个环判断有多少自同构,只需要正反跑两遍KMP即可
注意大小为2的环不存在翻转同构问题(即不需要考虑翻转,不过这题没有大小为2的环= =)
最后把所有贡献乘在一起就是答案
(我怎么跑得这么快啊这么快
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1010
#define MOD 1000000003
#define ORI1 2333
#define ORI2 23333
#define BASE1 999911657
#define BASE2 999911659
#define END1 18357
#define END2 81643
using namespace std;
int n,m;
long long ans=1;
long long fac[M];
unsigned long long A[M],B[M<<1];int len;
int next[M];
void Pretreatment()
{
int i;
for(fac[0]=1,i=1;i<=1000;i++)
fac[i]=fac[i-1]*i%MOD;
}
int KMP()
{
int i,fix=0,re=0;
for(i=2;i<=len;i++)
{
while( fix && A[fix+1]!=A[i] )
fix=next[fix];
if( A[fix+1]==A[i] )
++fix;
next[i]=fix;
}
for(i=1;i<=len;i++)
B[i]=B[i+len]=A[i];
fix=0;
for(i=1;i<len<<1;i++)
{
while( fix && A[fix+1]!=B[i] )
fix=next[fix];
if( A[fix+1]==B[i] )
++fix;
if(fix==len)
++re,fix=next[fix];
}
if(len>2)
{
for(i=1;i<len;i++)
swap(B[i],B[len+len-i]);
fix=0;
for(i=1;i<len<<1;i++)
{
while( fix && A[fix+1]!=B[i] )
fix=next[fix];
if( A[fix+1]==B[i] )
++fix;
if(fix==len)
++re,fix=next[fix];
}
}
return re;
}
namespace Tree{
int n,root;
struct abcd{
int to,next;
}table[M<<2];
int head[M<<1],tot;
int cg[2];
unsigned long long hash[M];
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
int Get_Centre_Of_Gravity(int x,int from)
{
int i,re=1,flag=true;
for(i=head[x];i;i=table[i].next)
if(table[i].to!=from)
{
int temp=Get_Centre_Of_Gravity(table[i].to,x);
if(temp<<1>n) flag=false;re+=temp;
}
if(n-re<<1>n) flag=false;
if(flag) (cg[0]?cg[1]:cg[0])=x;
return re;
}
void Tree_DP(int x,int from)
{
int i,top=0;
for(i=head[x];i;i=table[i].next)
if(table[i].to!=from)
Tree_DP(table[i].to,x);
static unsigned long long stack[M];
if(x<=::n)
{
for(i=head[x];i;i=table[i].next)
if(table[i].to!=from)
stack[++top]=hash[table[i].to];
sort(stack+1,stack+top+1);
int temp=0;
for(i=1;i<=top;i++)
{
++temp;
if(i==top||stack[i]!=stack[i+1])
{
(ans*=fac[temp])%=MOD;
temp=0;
}
}
hash[x]=ORI1;
for(i=1;i<=top;i++)
(((hash[x]*=BASE1)+=stack[i])^=stack[i])+=stack[i];
((hash[x]+=END1)*=END1)^=END1;
}
else if(x!=root)
{
for(i=head[x];i;i=table[i].next)
if(table[i].to==from)
break;
for(i=table[i].next;i;i=table[i].next)
stack[++top]=hash[table[i].to];
for(i=head[x];table[i].to!=from;i=table[i].next)
stack[++top]=hash[table[i].to];
for(i=1;i<=top;i++)
if(stack[i]!=stack[top+1-i])
break;
if(top>=2&&i==top+1)
(ans<<=1)%=MOD;
unsigned long long hash1,hash2;
hash1=ORI2;
for(i=1;i<=top;i++)
(((hash1*=BASE2)+=stack[i])^=stack[i])+=stack[i];
((hash1+=END2)*=END2)^=END2;
hash2=ORI2;
for(i=top;i;i--)
(((hash2*=BASE2)+=stack[i])^=stack[i])+=stack[i];
((hash2+=END2)*=END2)^=END2;
hash[x]=min(hash1,hash2);
}
else
{
for(i=head[x];i;i=table[i].next)
A[++len]=hash[table[i].to];
(ans*=KMP())%=MOD;
}
}
void Calculate()
{
int i;
Get_Centre_Of_Gravity(1,0);
if(!cg[1])
root=cg[0];
else
{
root=++n;
for(i=head[cg[0]];i;i=table[i].next)
if(table[i].to==cg[1])
{
table[i].to=root;
break;
}
for(i=head[cg[1]];i;i=table[i].next)
if(table[i].to==cg[0])
{
table[i].to=root;
break;
}
Add(root,cg[0]);
Add(root,cg[1]);
}
Tree_DP(root,0);
}
}
namespace Cactus{
struct abcd{
int to,next;
}table[M<<2];
int head[M],tot=1;
bool v[M],over[M],on_ring[M];
int from[M];
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
void DFS(int x,int from)
{
int i,j;
v[x]=true;
for(i=head[x];i;i=table[i].next)
if(i^from^1)
{
if(!v[table[i].to])
{
Cactus::from[table[i].to]=x;
on_ring[x]=false;
DFS(table[i].to,i);
if(!on_ring[x])
{
Tree::Add(x,table[i].to);
Tree::Add(table[i].to,x);
}
}
else
{
if(over[table[i].to])
continue;
++Tree::n;
for(j=x;;j=Cactus::from[j])
{
Tree::Add(Tree::n,j);
Tree::Add(j,Tree::n);
on_ring[j]=true;
if(j==table[i].to)
break;
}
}
}
over[x]=true;
}
}
int main()
{
int i,x,y;
cin>>n>>m;
Tree::n=n;
Pretreatment();
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
Cactus::Add(x,y);
Cactus::Add(y,x);
}
Cactus::DFS(1,0);
Tree::Calculate();
cout<<ans<<endl;
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-19 06:38:08