[noip模擬賽]小U的女裝
阿新 • • 發佈:2018-11-01
https://www.zybuluo.com/ysner/note/1329304
題面
有一張\(n\)點\(m\)邊的、不一定聯通的無向圖。
如果選了一條邊,就不能選其兩個端點。
現在同時選點和邊,那麼最多能夠選的點邊數量和為多少。
同時,回答使點邊數最大的方案數。
\(n\leq10^5,m\leq3*10^5\)
解析
設答案為\(ans\),方案數為\(tot\)。
討論一下聯通塊的形態:- \(m=n-1\):\(ans=n,tot=1\)
- \(m=n\):\(ans=m\),環中\(tot=2\),樹的部分\(tot\)值可以通過\(dp\)求出
\(m>n\):\(ans=m\)
樹的部分的\(dp\):
設\(dp[i][0/1]\)表示統計到\(i\)號點,選不選該點的方案數。
然後從兒子轉移,討論一下就行。
綜上,其實把強聯通分量縮點後直接樹形\(DP\)就行了。
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define ll long long #define re register #define il inline #define fp(i,a,b) for(re int i=a;i<=b;++i) #define fq(i,a,b) for(re int i=a;i>=b;--i) using namespace std; const int N=5e5+100,mod=998244353; int n,m,h[N],cnt=1,ans,dfn[N],low[N],sta[N],top,tot,sz[N],bl[N],scc,Esz[N],f[2][N],g[2][N]; bool vis[N]; struct dat{int u,v;}a[N<<1]; struct Edge{int to,nxt;}e[N<<1]; il void add(re int u,re int v) { e[++cnt]=(Edge){v,h[u]};h[u]=cnt; e[++cnt]=(Edge){u,h[v]};h[v]=cnt; } il ll gi() { re ll x=0,t=1; re char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); if(ch=='-') t=-1,ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); return x*t; } il void Tarjan(re int u,re int las) { dfn[u]=low[u]=++tot;sta[++top]=u;vis[u]=1; re int v; for(re int i=h[u];i+1;i=e[i].nxt) if((i^1)^las) { re int v=e[i].to; if(!dfn[v]) Tarjan(v,i),low[u]=min(low[u],low[v]); else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { ++scc; do{v=sta[top--];vis[v]=0;++sz[scc];bl[v]=scc;}while(u^v); } } il void dfs(re int u) { f[0][u]=sz[u];f[1][u]=Esz[u];g[0][u]=g[1][u]=1;vis[u]=1; for(re int i=h[u];i+1;i=e[i].nxt) { re int v=e[i].to; if(vis[v]) continue; dfs(v); if(f[0][v]>f[1][v]) f[0][u]+=f[0][v],g[0][u]=1ll*g[0][u]*g[0][v]%mod; if(f[0][v]==f[1][v]) f[0][u]+=f[0][v],g[0][u]=1ll*g[0][u]*(g[0][v]+g[1][v])%mod; if(f[0][v]<f[1][v]) f[0][u]+=f[1][v],g[0][u]=1ll*g[0][u]*g[1][v]%mod; if(f[0][v]>f[1][v]+1) f[1][u]+=f[0][v],g[1][u]=1ll*g[1][u]*g[0][v]%mod; if(f[0][v]==f[1][v]+1) f[1][u]+=f[0][v],g[1][u]=1ll*g[1][u]*(g[0][v]+g[1][v])%mod; if(f[0][v]<f[1][v]+1) f[1][u]+=f[1][v]+1,g[1][u]=1ll*g[1][u]*g[1][v]%mod; } } int main() { memset(h,-1,sizeof(h)); n=gi();m=gi(); fp(i,1,m) a[i].u=gi(),a[i].v=gi(),add(a[i].u,a[i].v); fp(i,1,n) if(!dfn[i]) Tarjan(i,0); memset(h,-1,sizeof(h));cnt=0; fp(i,1,m) { re int u=a[i].u,v=a[i].v; if(bl[u]^bl[v]) add(bl[u],bl[v]); else ++Esz[bl[u]]; } n=scc;tot=1; fp(i,1,n) if(!vis[i]) { dfs(i); if(f[0][i]<f[1][i]) ans+=f[1][i],tot=1ll*tot*g[1][i]%mod; if(f[0][i]==f[1][i]) ans+=f[1][i],tot=1ll*tot*(g[0][i]+g[1][i])%mod; if(f[0][i]>f[1][i]) ans+=f[0][i],tot=1ll*tot*g[0][i]%mod; } printf("%d\n%d\n",ans,tot); return 0; }