題目鏈接:
題目大意:
仙人掌(Cactus)被定義爲每條邊(紫薯上此處寫成 每個點,巨坑)最多在一個簡單迴路上的連通無向圖。(簡單迴路指結點不重複經過的環)。
給定一個無向圖,求它有多少生成子圖(包括自身)是仙人掌。如果原圖不是仙人掌,輸出0。
題解:
子圖:原圖的一部分。
生成子圖:包含原圖所有點的子圖。
相當於拆去原圖的一些邊,使得圖仍然是一個仙人掌。
在原圖爲仙人掌的前提下,拆去的邊一定是環上的邊,切一個環最多拆一條邊,所以單獨考慮一個環能拆的方案數爲環的邊數加一。因爲是仙人掌,每個環不共邊,所以每個環拆邊是獨立的,整個圖的方案數爲所有環的方案數的乘積。
仙人掌上每個環構成一個雙連通分量,且連通分量內點數等於邊數。所以可以通過求雙連通分量,再判斷是否每一個雙連通分量內的點數均等於邊數,來判斷無向圖是否是一個仙人掌。
注意只有兩個點的連通分量不在考慮範圍內。
如果是仙人掌,最終答案爲大於2的連通分量的大小加一的乘積,否則爲0。
*最終的結果可能非常大,最大的達到了六千多爲數(天坑)。。。
代碼:
#include <bits/stdc++.h>
#define LL long long
#define LD long double
#define ULL unsigned long long
#define UI unsigned int
#define PII pair<int,int>
#define MPII(x,y) pair<int,int>{x,y}
#define _for(i,j,k) for(int i=j;i<=k;i++)
#define for_(i,j,k) for(int i=j;i>=k;i--)
#define efor(i,u) for(int i=head[u];i;i=net[i])
#define lowbit(x) (x&-x)
#define ls(x) x<<1
#define rs(x) x<<1|1
#define inf 0x3fffffff
//#pragma comment(linker, "/STACK:10240000000,10240000000")
using namespace std;
const int maxn = 6e6 + 5;
const int M = 1e9 + 7;
inline int mad(int a,int b){return (a+=b)>=M?a-M:a;}
//大數模板
#define MAXN 9999
#define MAXSIZE 1010
#define DLEN 4
class BigNum {
private:
int a[7000]; //位數可變
int len;
public:
BigNum() {
len=1;
memset(a,0,sizeof(a));
}
BigNum(const int);
BigNum(const char*);
BigNum(const BigNum &);
BigNum &operator=(const BigNum &);
friend istream& operator>>(istream&,BigNum&);
friend ostream& operator<<(ostream&,BigNum&);
BigNum operator+(const BigNum &)const;
BigNum operator-(const BigNum &)const;
BigNum operator*(const BigNum &)const;
BigNum operator/(const int &)const;
BigNum operator^(const int &)const;
int operator%(const int &)const;
bool operator>(const BigNum &T)const;
bool operator>(const int &t)const;
void print();
};
BigNum::BigNum(const int b) {
int c,d=b;
len=0;
memset(a,0,sizeof(a));
while(d>MAXN) {
c=d-(d/(MAXN+1))*(MAXN+1);
d=d/(MAXN+1);
a[len++]=c;
}
a[len++]=d;
}
BigNum::BigNum(const char *s) {
int t,k,index,L,i;
memset(a,0,sizeof(a));
L=strlen(s);
len=L/DLEN;
if(L%DLEN)len++;
index=0;
for(i=L-1; i>=0; i-=DLEN) {
t=0;
k=i-DLEN+1;
if(k<0)k=0;
for(int j=k; j<=i; j++)
t=t*10+s[j]-'0';
a[index++]=t;
}
}
BigNum::BigNum(const BigNum &T):len(T.len) {
int i;
memset(a,0,sizeof(a));
for(i=0; i<len; i++)
a[i]=T.a[i];
}
BigNum& BigNum::operator=(const BigNum &n) {
int i;
len=n.len;
memset(a,0,sizeof(a));
for(i=0; i<len; i++) a[i]=n.a[i];
return *this;
}
istream& operator>>(istream &in,BigNum &b) {
char ch[MAXSIZE*4];
int i=-1;
in>>ch;
int L=strlen(ch);
int count=0,sum=0;
for(i=L-1; i>=0;) {
sum=0;
int t=1;
for(int j=0; j<4&&i>=0; j++,i--,t*=10) {
sum+=(ch[i]-'0')*t;
}
b.a[count]=sum;
count++;
}
b.len=count++;
return in;
}
ostream& operator<<(ostream& out,BigNum& b) {
int i;
cout<<b.a[b.len-1];
for(i=b.len-2; i>=0; i--) {
printf("%04d",b.a[i]);
}
return out;
}
BigNum BigNum::operator+(const BigNum &T)const {
BigNum t(*this);
int i,big;
big=T.len>len?T.len:len;
for(i=0; i<big; i++) {
t.a[i]+=T.a[i];
if(t.a[i]>MAXN) {
t.a[i+1]++;
t.a[i]-=MAXN+1;
}
}
if(t.a[big]!=0) t.len=big+1;
else t.len=big;
return t;
}
BigNum BigNum::operator-(const BigNum &T)const {
int i,j,big;
bool flag;
BigNum t1,t2;
if(*this>T) {
t1=*this;
t2=T;
flag=0;
} else {
t1=T;
t2=*this;
flag=1;
}
big=t1.len;
for(i=0; i<big; i++) {
if(t1.a[i]<t2.a[i]) {
j=i+1;
while(t1.a[j]==0) j++;
t1.a[j--]--;
while(j>i) t1.a[j--]+=MAXN;
t1.a[i]+=MAXN+1-t2.a[i];
} else t1.a[i]-=t2.a[i];
}
t1.len=big;
while(t1.a[len-1]==0 && t1.len>1) {
t1.len--;
big--;
}
if(flag) t1.a[big-1]=0-t1.a[big-1];
return t1;
}
BigNum BigNum::operator*(const BigNum &T)const {
BigNum ret;
int i,j,up;
int temp,temp1;
for(i=0; i<len; i++) {
up=0;
for(j=0; j<T.len; j++) {
temp=a[i]*T.a[j]+ret.a[i+j]+up;
if(temp>MAXN) {
temp1=temp-temp/(MAXN+1)*(MAXN+1);
up=temp/(MAXN+1);
ret.a[i+j]=temp1;
} else {
up=0;
ret.a[i+j]=temp;
}
}
if(up!=0) ret.a[i+j]=up;
}
ret.len=i+j;
while(ret.a[ret.len-1]==0 && ret.len>1)ret.len--;
return ret;
}
BigNum BigNum::operator/(const int &b)const {
BigNum ret;
int i,down=0;
for(i=len-1; i>=0; i--) {
ret.a[i]=(a[i]+down*(MAXN+1))/b;
down=a[i]+down*(MAXN+1)-ret.a[i]*b;
}
ret.len=len;
while(ret.a[ret.len-1]==0 && ret.len>1) ret.len--;
return ret;
}
int BigNum::operator%(const int &b)const {
int i,d=0;
for(i=len-1; i>=0; i--)
d=(((long long)d*(MAXN+1))%b+a[i])%b;
return d;
}
BigNum BigNum::operator^(const int &n)const {
BigNum t,ret(1);
int i;
if(n<0)exit(-1);
if(n==0)return 1;
if(n==1)return *this;
int m=n;
while(m>1) {
t=*this;
for(i=1; (i<<1)<=m; i<<=1) t=t*t;
m-=i;
ret=ret*t;
if(m==1)ret=ret*(*this);
}
return ret;
}
bool BigNum::operator>(const BigNum &T)const {
int ln;
if(len>T.len)return true;
else if(len==T.len) {
ln=len-1;
while(a[ln]==T.a[ln]&&ln>=0) ln--;
if(ln>=0 && a[ln]>T.a[ln]) return true;
else return false;
} else
return false;
}
bool BigNum::operator>(const int &t)const {
BigNum b(t);
return *this>b;
}
void BigNum::print() {
int i;
printf("%d",a[len-1]);
for(i=len-2; i>=0; i--)
printf("%04d",a[i]);
printf("\n");
}
BigNum bm;
int head[maxn],net[maxn],e[maxn],cnt,n,m;
bool flag;
LL an;
void add(int u,int v){
e[++cnt]=v;
net[cnt]=head[u];
head[u]=cnt;
}
//BCC
int df,dfn[maxn],low[maxn],bccn[maxn],bc;
int isc[maxn];//割點
vector<int> bcc[maxn];
stack<int> st;
void tarjan(int u,int pre){
dfn[u]=low[u]= ++df;
int child=0;
st.push(u);
for(int i=head[u];i;i=net[i]){
if(!dfn[e[i]]){
child++;
tarjan(e[i],u);
low[u]=min(low[u],low[e[i]]);
if(low[e[i]]>=dfn[u]){
isc[u]=1;
bc++;bcc[bc].clear();
bcc[bc].push_back(u);bccn[u]=bc;
while(bccn[e[i]]!=bc){
bcc[bc].push_back(st.top());
bccn[st.top()]=bc;
st.pop();
}
if(bcc[bc].size()>2){
int ct=0;
for(auto x:bcc[bc]){
for(int j=head[x];j;j=net[j]){
if(bccn[e[j]]==bc){
ct++;
}
}
}
//cout<<ct<<" "<<bcc[bc].size()<<endl;
if(ct!=2*bcc[bc].size()) flag=false;
//an = (LL)an*(ct/2+1ll);
if(flag){
bm = bm*(ct/2+1);
}
}
}
}
else if(dfn[e[i]]<dfn[u]&&e[i]!=pre){
low[u]=min(low[u],dfn[e[i]]);
}
}
if(pre==0&&child==1) isc[u]=0;
}
int find_bcc(){
int ret=0;
df=bc=0;
for(int i=1;i<=n;++i) dfn[i]=low[i]=isc[i]=bccn[i]=0;
for(int i=1;i<=n;++i) if(!dfn[i]){
ret++;
if(ret>1) break;
while(!st.empty()) st.pop();
tarjan(i,0);
}
return ret;
}
int main(){
int fst=0;
while(scanf("%d %d",&n,&m)==2){
if(fst) cout<<"\n";
else fst++;
flag=true;an=1ll;bm=1;
int k,u,v;
_for(i,1,m){
scanf("%d %d",&k,&u);
_for(j,2,k){
scanf("%d",&v);
add(u,v);
add(v,u);
u=v;
}
}
int bcnt = find_bcc();
// cout<<bcnt<<" "<<flag<<endl;
if(bcnt!=1) flag=false;
if(flag){
cout<<bm<<"\n";
//cout<<an<<"\n";
}
else{
cout<<"0\n";
}
_for(i,1,n) head[i]=0;
cnt=0;
}
return 0;
}