其實就是BZOJ3899的加強版
當時寫的東西真是不敢恭維
還是看Po姐的題解吧
我們把仙人掌拆成圓方樹 就可以直接用樹hash來做
先找重心 因為我寫的時候把兩個點也當做點雙 那麼所有邊都是圓方相接如果重心有兩個 去代表環的方點就好了
接下來是hash 圓點沒問題 子樹排完序hash 順帶記一下如果有相同 答案乘上出現次數的階乘
不是根的方點 也就是一個環 是有順序的 不能排序 然後看一下翻轉是不是一樣 乘個2
最後如果根是一個方點 那麼我們要考慮環的同構 環翻轉前後跑一通KMP就知道有幾種情況是循環同構的 乘上答案
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<stack>
#include<set>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> abcd;
inline char nc(){
static char buf[],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,,,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-;
for (x=;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=,P=e9+;
int prime[N],num;
int q[N];
int vst[N],d[N];
inline void Pre(int n){
for (int i=;i<=n;i++){
if (!vst[i]) prime[++num]=i,d[i]=i;
for (int j=;j<=num && (ll)i*prime[j]<=n;j++){
vst[i*prime[j]]=; d[i*prime[j]]=prime[j];
if (i%prime[j]==) break;
}
}
}
int _q[N];
inline void Print(int n){
for (int i=n;i;i--){
_q[i]+=_q[i+1];
if (_q[i]){
int t=i;
while (t>)
q[d[t]]+=_q[i],t/=d[t];
}
}
int tot=;
for (int i=;i<=n;i++) tot+=q[i]!=;
printf("%d\n",tot);
for (int i=;i<=n;i++)
if (q[i])
printf("%d %d\n",i,q[i]);
}
const ull ORI1=,ORI2=;
const ull BASE1=,BASE2=;
const ull END1=,END2=;
struct edge{
int u,v,next;
}G[N<<];
int head[N],inum=;
#define V G[p].v
inline void add(int u,int v){
int p=++inum; G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int n,m,bcc;
int size[N],minv=<<,rt;
inline void Root(int u,int fa){
size[u]=; int maxv=;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
Root(V,u),size[u]+=size[V],maxv=max(maxv,size[V]);
maxv=max(maxv,n+bcc-size[u]);
if (maxv<minv || (maxv==minv && u>rt)) rt=u,minv=maxv;
}
ull lst[N]; int pnt;
ull H[N];
int nxt[N];
ull b[N];
inline int KMP(ull *a,int n){
int k=; nxt[]=;
for (int i=;i<=n;i++){
while (k && a[k+]!=a[i]) k=nxt[k];
if (a[k+]==a[i]) k++;
nxt[i]=k;
}
for (int i=;i<=n;i++) b[i]=b[n+i]=a[i];
k=; int ret=;
for (int i=;i<n+n;i++){
while (k && a[k+]!=b[i]) k=nxt[k];
if (a[k+]==b[i]) k++;
if (k==n) k=nxt[k],ret++;
}
if (n>){
reverse(b+,b+n+n+); k=;
for (int i=;i<n+n;i++){
while (k && a[k+]!=b[i]) k=nxt[k];
if (a[k+]==b[i]) k++;
if (k==n) k=nxt[k],ret++;
}
}
return ret;
}
inline void dfs(int u,int fa){
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
dfs(V,u);
pnt=;
if (u<=n){
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
lst[++pnt]=H[V];
sort(lst+,lst+pnt+);
int tmp=;
for (int i=;i<=pnt;i++){
tmp++;
if (i==pnt || lst[i]!=lst[i+])
_q[tmp]++,tmp=;
}
H[u]=ORI1;
for (int i=;i<=pnt;i++) (((H[u]*=BASE1)+=lst[i])^=lst[i])+=lst[i];
((H[u]+=END1)*=END1)^=END1;
}else if (u!=rt){
int k;
for (int p=head[u];p;p=G[p].next)
if (V==fa) { k=p; break; }
for (int p=G[k].next;p;p=G[p].next)
lst[++pnt]=H[V];
for (int p=head[u];p!=k;p=G[p].next)
lst[++pnt]=H[V];
ull H1,H2;
H1=ORI2;
for (int i=;i<=pnt;i++) (((H1*=BASE2)+=lst[i])^=lst[i])+=lst[i];
((H1+=END2)*=END2)^=END2;
H2=ORI2;
for (int i=pnt;i;i--) (((H2*=BASE2)+=lst[i])^=lst[i])+=lst[i];
((H2+=END2)*=END2)^=END2;
H[u]=min(H1,H2);
if (pnt>= && H1==H2)
_q[2]++;
}else{
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
lst[++pnt]=H[V];
int ret=KMP(lst,pnt),t=ret;
for (int i=;i<=num && prime[i]<=ret;i++)
while (t%prime[i]==)
t/=prime[i],q[prime[i]]++;
}
}
namespace Cac{
struct edge{
int u,v,next;
}G[N<<];
int head[N],inum=;
inline void add(int u,int v){
int p=++inum; G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
set<abcd> Set;
inline void Add(int u,int v){
if (u>v) swap(u,v); if (!Set.count(abcd(u,v))) Set.insert(abcd(u,v)),add(u,v),add(v,u);
}
int pre[N],low[N],clk;
stack<int> sta;
inline void dfs(int u,int fa){
pre[u]=low[u]=++clk; sta.push(u);
for (int p=head[u];p;p=G[p].next)
if (p^fa^)
if (!pre[V]){
dfs(V,p);
low[u]=min(low[u],low[V]);
if (low[V]>=pre[u]){
++bcc;
while (sta.top()!=u){
int t=sta.top(); sta.pop();
::add(n+bcc,t),::add(t,n+bcc);
if (t==V) break;
}
::add(n+bcc,u); ::add(u,n+bcc);
}
}else
low[u]=min(low[u],pre[V]);
}
inline void Read(){
int k,x,y;
read(m);
while (m--){
read(k); read(x);
for (int i=;i<=k;i++)
read(y),Add(x,y),x=y;
}
dfs(,);
}
}
int main(){
freopen("cactus.in","r",stdin);
freopen("cactus.out","w",stdout);
read(n); Pre(n<<);
Cac::Read();
Root(,);
dfs(rt,);
Print(n<<);
return ;
}