这好像不难啊 考场上智商掉线了吧 可能是脑袋被吃掉了吧
先说正经的
这个题 要是不是棵仙人掌 那么就无解
要是是棵树 直接树形DP
那仙人掌呢 把所有环上的边拆掉 对剩下的森林中的每棵树DP 然后乘法原理就好了
然后 做完了…
还是不知道考场上在干什么
我可能忍不住分享下自己的悲惨经历啊
考场上想出了树形DP 然后就没有然后了? 尼玛仙人掌这么好想 就被我弃了?!
行吧 考挂不如狗 下午切这道题 结果先是常量 N 和 M 不分 数组大小乱开?
然后是数据范围看错?
UOJ上目前全部70分都是我交的?
我真是不知道自己在干什么
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> abcd;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*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());
}
const int N=500005;
const int M=1000005;
const int P=998244353;
const int INV2=(P+1)>>1;
ll fac[N],inv[N],pw[N];
inline void Pre(int n){
fac[0]=1; for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;
inv[1]=1; for (int i=2;i<=n;i++) inv[i]=(ll)(P-P/i)*inv[P%i]%P;
inv[0]=1; for (int i=1;i<=n;i++) inv[i]=inv[i-1]*inv[i]%P;
pw[0]=1; for (int i=1;i<=n;i++) pw[i]=pw[i-1]*INV2%P;
}
struct edge{
int u,v,next;
}G[M<<1];
int head[N],inum;
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 tag[N];
int fat[N],depth[N];
#define V G[p].v
inline void dfs_j(int u,int fa){
fat[u]=fa; depth[u]=depth[fa]+1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
if (!depth[V])
dfs_j(V,u),tag[u]+=tag[V];
else if (depth[V]<depth[u])
tag[u]++,tag[V]--;
}
int fap[N]; bool ed[M];
inline void find(int u,int fa){
fat[u]=fa; depth[u]=depth[fa]+1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
if (!depth[V])
fap[V]=p>>1,find(V,u);
else if (depth[V]<depth[u]){
int t=u; ed[p>>1]=1;
while (t!=V)
ed[fap[t]]=1,t=fat[t];
}
}
bool vst[N]; ll f[N];
inline ll C(int n,int a){
return fac[n]*inv[n-2*a]%P*inv[a]%P*pw[a]%P;
}
inline void dfs(int u,int fa){
vst[u]=1; int cnt=0;
f[u]=1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
dfs(V,u),f[u]=f[u]*f[V]%P,cnt++;
ll tmp=0;
for (int i=0;i<=cnt/2;i++)
tmp+=C(cnt,i)*(!fa?1:(cnt-2*i+1))%P;
tmp%=P;
f[u]=f[u]*tmp%P;
}
int n,m;
int x[M],y[M];
int main(){
int T;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(T); Pre(500000);
while (T--){
read(n); read(m);
for (int i=1;i<=n;i++) head[i]=0; inum=1;
for (int i=1;i<=m;i++){
read(x[i]),read(y[i]); if (x[i]>y[i]) swap(x[i],y[i]);
add(x[i],y[i],++inum),add(y[i],x[i],++inum);
}
for (int i=1;i<=n;i++) depth[i]=fat[i]=tag[i]=0;
dfs_j(1,0);
int flag=0; for (int i=1;i<=n;i++) flag|=tag[i]>1;
if (flag){
printf("0\n"); continue;
}
for (int i=1;i<=n;i++) depth[i]=fat[i]=0;
for (int i=1;i<=m;i++) ed[i]=0;
find(1,0);
for (int i=1;i<=n;i++) head[i]=0; inum=1;
for (int i=1;i<=m;i++)
if (!ed[i])
add(x[i],y[i],++inum),add(y[i],x[i],++inum);
for (int i=1;i<=n;i++) f[i]=vst[i]=0;
ll ans=1;
for (int i=1;i<=n;i++)
if (!vst[i])
dfs(i,0),ans=ans*f[i]%P;
printf("%lld\n",ans);
}
return 0;
}
UPD 再次被自己傻哭 根本不用树形DP啊
直接
ans=Π Fdegi
就好了
F
<script type="math/tex" id="MathJax-Element-51">F</script>表示配对的方案数 因为每个点的度怎么配是不相互影响的 反正就是怎么连都只可能是链
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> abcd;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*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());
}
const int N=500005;
const int M=1000005;
const int P=998244353;
const int INV2=(P+1)>>1;
ll fac[N],inv[N],pw[N];
ll F[N];
inline void Pre(int n){
fac[0]=1; for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;
inv[1]=1; for (int i=2;i<=n;i++) inv[i]=(ll)(P-P/i)*inv[P%i]%P;
inv[0]=1; for (int i=1;i<=n;i++) inv[i]=inv[i-1]*inv[i]%P;
pw[0]=1; for (int i=1;i<=n;i++) pw[i]=pw[i-1]*INV2%P;
F[0]=F[1]=1; for (int i=2;i<=n;i++) F[i]=(F[i-1]+F[i-2]*(i-1)%P)%P;
}
struct edge{
int u,v,next;
}G[M<<1];
int head[N],inum;
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 tag[N];
int fat[N],depth[N];
#define V G[p].v
inline void dfs_j(int u,int fa){
fat[u]=fa; depth[u]=depth[fa]+1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
if (!depth[V])
dfs_j(V,u),tag[u]+=tag[V];
else if (depth[V]<depth[u])
tag[u]++,tag[V]--;
}
int fap[N]; bool ed[M];
inline void find(int u,int fa){
fat[u]=fa; depth[u]=depth[fa]+1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
if (!depth[V])
fap[V]=p>>1,find(V,u);
else if (depth[V]<depth[u]){
int t=u; ed[p>>1]=1;
while (t!=V)
ed[fap[t]]=1,t=fat[t];
}
}
int deg[N];
int n,m;
int x[M],y[M];
int main(){
int T;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(T); Pre(500000);
while (T--){
read(n); read(m);
for (int i=1;i<=n;i++) head[i]=0; inum=1;
for (int i=1;i<=m;i++){
read(x[i]),read(y[i]); if (x[i]>y[i]) swap(x[i],y[i]);
add(x[i],y[i],++inum),add(y[i],x[i],++inum);
}
for (int i=1;i<=n;i++) depth[i]=fat[i]=tag[i]=0;
dfs_j(1,0);
int flag=0; for (int i=1;i<=n;i++) flag|=tag[i]>1;
if (flag){
printf("0\n"); continue;
}
for (int i=1;i<=n;i++) depth[i]=fat[i]=0;
for (int i=1;i<=m;i++) ed[i]=0;
find(1,0);
for (int i=1;i<=n;i++) deg[i]=0;
for (int i=1;i<=m;i++)
if (!ed[i])
deg[x[i]]++,deg[y[i]]++;
ll ans=1;
for (int i=1;i<=n;i++)
ans=ans*F[deg[i]]%P;
printf("%lld\n",ans);
}
return 0;
}