AtCoder ABC 222E
阿新 • • 發佈:2021-10-10
分析
首先,我們可通過DFS處理出來,在沿著a陣列給的順序走時,每條邊都經過了多少次。我們假設第i
條邊被經過的次數為\(c_i\)次,則問題可以轉化為,從\(c_1,c_2...c_{n-1}\)中,分成兩部分,使得一部分構成R,一部分構成B,從而使得R-B=K?我們設S=\(c_1+c_2+...+c_{n-1}\),而又因為R+B=S,因此我們可以解出
因此,問題在此進行傳化,從\(c_1,c_2...c_{n-1}\)中,挑選出一部分數,使得其和為\(\frac{S+K}{2}\)?
問題到這裡,已經很明顯了,01揹包計數問題
但有一些細節需要處理,當S+K是奇數的時候,是無解的,同時S+K是負數也無解。
接下來就是01計數揹包
\[f[i][j]=從c_1,c_2...,c_i中選擇和為j的方案數 \]AcCode
#include <bits/stdc++.h> #define x first #define y second #define debug(x) cout<<#x" ----> "<<x<<endl using namespace std; const int N = 1010,M=N*2,INF = 0x3f3f3f3f,mod=998244353; const double eps = 1e-10; const double pi = acos(-1.0); typedef pair<int, int> PII ; typedef pair<double,double> PDD; typedef long long LL; int h[N],e[M],ne[M],idx; int cnt[N]; int w[N]; int dp[100001]; int n,m,k; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } bool dfs(int u,int fa,int end) { if(u==end) return 1; for(int i=h[u];~i;i=ne[i]) { int j = e[i]; if(j==fa) continue; if(dfs(j,u,end)) { cnt[i/2]++; return 1; } } return 0; } void solve() { memset(h,-1,sizeof h); idx=0; cin>>n>>m>>k; for(int i=0;i<m;i++) cin>>w[i]; for(int i=0;i<n-1;i++) { int u,v; cin>>u>>v; add(u,v),add(v,u); } for(int i=0;i<m-1;i++) dfs(w[i],-1,w[i+1]); int s = 0; for(int i=0;i<n-1;i++) s+=cnt[i]; if((s+k)%2||s+k<0) { cout<<0<<endl; return ; } dp[0]=1; for(int i=0;i<n-1;i++) for(int x=100000;x>=cnt[i];x--) dp[x]=(LL)(dp[x]+dp[x-cnt[i]])%mod; cout << dp[(s+k)/2]<<endl; } int main() { int t=1; while(t -- ) { solve(); } return 0; }