匹配(树形DP)
傳送門
題目描述:
有一張無向聯(lián)通圖 G=?V,E? ,其中頂點(diǎn)數(shù) |V|=n ,邊數(shù) |E|=n?1 。求有多少種方案使得刪邊后殘余圖中的最大匹配數(shù)恰好為 m 的倍數(shù)。
題解:
這道題看起來是求最大匹配,其實(shí)關(guān)系不大,正解是樹形DP
定義一個(gè)數(shù)組dp[i][j][k], 其中
i表示節(jié)點(diǎn),
j表示i的子樹中的最大匹配數(shù)%m,
k表示i是否與其子節(jié)點(diǎn)匹配.
接下來推一下合并兩顆子樹u,v的遞推式即可
注意幾個(gè)細(xì)節(jié):
1.用快讀,否則會(huì)TLE
2.盡量少取余,否則會(huì)很慢
3.有2n條邊,我一開始就因?yàn)閿?shù)組開小了卡了很久
4.dp[i][j][k]上一次的結(jié)果不帶入這一次,要另開一個(gè)tmp數(shù)組來執(zhí)行操作
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } const int N=50010; const int M=200; const int mod=998244353; int n,m; struct Edge{int v,nxt; }edge[N<<1]; ll dp[N][M][2],tmp[M][2]; int head[N],cnt,fa[N],sz[N]; void add_edge(int u,int v){edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt; } void dfs(int u){sz[u]=1;dp[u][0][0]=1;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa[u]) continue;fa[v]=u;dfs(v);for(int i=0;i<m;i++) tmp[i][0]=tmp[i][1]=0;for(int j=0;j<=sz[u]&&j<m;j++){for(int k=0;k<=sz[v]&&k<m;k++){int v1=(j+k+1)%m,v2=(j+k)%m;tmp[v1][1]+=dp[u][j][0]*dp[v][k][0];tmp[v1][1]%=mod;tmp[v2][0]+=dp[u][j][0]*dp[v][k][0]+dp[u][j][0]*dp[v][k][1]*2;tmp[v2][0]%=mod;tmp[v2][1]+=dp[u][j][1]*dp[v][k][0]*2+dp[u][j][1]*dp[v][k][1]*2;tmp[v2][1]%=mod;}}for(int i=0;i<m;i++){dp[u][i][0]=tmp[i][0];dp[u][i][1]=tmp[i][1];}sz[u]+=sz[v];} } int main(){n=read();m=read();for(int i=1;i<n;i++){int u=read();int v=read();add_edge(u,v);add_edge(v,u);}dfs(1);printf("%d\n",(dp[1][0][0]+dp[1][0][1])%mod);return 0; }總結(jié)
- 上一篇: 气候和天气有什么区别气候跟天气有什么区别
- 下一篇: 来看看Win11系统新的自动播放界面,是