AtCoder Beginner Contest 222 E - Red and Blue Tree(dfs dp)

linkkkkk

题意:

给出 n n n个点的树和长度为 m m m的序列 a a a。现需要给每条边染成 r e d / b l u e red/blue red/blue色,要求按照 a a a走的路径,经过的边数 r − b = k r-b=k rb=k,问方案数。

思路:

  • 首先可以通过 d f s dfs dfs将序列 a a a的路径经过每条边的次数 c i c_i ci统计出来。这样问题就变成了从 c 1 , c 2 , … … c n − 1 c_1,c_2,……c_{n-1} c1,c2,cn1中选择一些数和为 r r r,剩余的数和为 b b b,满足 r − b = k r-b=k rb=k
  • 假设 s u m = c 1 + c 2 + … … + c n − 1 sum=c_1+c_2+……+c_{n-1} sum=c1+c2++cn1,那么就可以得到 r + b = s u m , r − b = k r+b=sum,r-b=k r+b=sum,rb=k,解得 r = s u m + k 2 r=\frac{sum+k}{2} r=2sum+k
  • 问题变成了从 c 1 , c 2 , … … c n − 1 c_1,c_2,……c_{n-1} c1,c2,cn1中选择一些数使得和为 s u m + k 2 \frac{sum+k}{2} 2sum+k
  • d p [ i ] [ j ] dp[i][j] dp[i][j]表示从前 i i i个数中选,和为 j j j的方案数。将第一维去掉,第二层循环变成倒序,跟背包一样的。
  • 上限的话, k = 1 e 5 k=1e5 k=1e5,假设 a a a序列的相邻两个点为直径端点,每次都走 1 e 3 1e3 1e3,一共走 1 e 5 1e5 1e5,每条边都是 100 次 100次 100,和为 1 e 5 1e5 1e5,这样 ( k + s u m ) / 2 (k+sum)/2 (k+sum)/2还是 1 e 5 1e5 1e5,所以取 1 e 5 1e5 1e5就够用啦。

代码:

// Problem: E - Red and Blue Tree
// Contest: AtCoder - Exawizards Programming Contest 2021(AtCoder Beginner Contest 222)
// URL: https://atcoder.jp/contests/abc222/tasks/abc222_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include
using namespace std;
typedef long long ll;typedef unsigned long long ull;
typedef pair<ll,ll>PLL;typedef pair<int,int>PII;typedef pair<double,double>PDD;
#define I_int ll
inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
#define read read()
#define rep(i, a, b) for(int i=(a);i<=(b);++i)
#define dep(i, a, b) for(int i=(a);i>=(b);--i)
ll ksm(ll a,ll b,ll p){ll res=1;while(b){if(b&1)res=res*a%p;a=a*a%p;b>>=1;}return res;}
const int maxn=4e5+7,maxm=1e6+7,mod=998244353;

int n,m,k,a[110],c[1100],dp[maxm];
vector<PII>g[1100];

int dfs(int u,int fa,int e){
	if(e==u) return 1;
	for(auto t:g[u]){
		int j=t.first,id=t.second;
		if(j==fa) continue;
		if(dfs(j,u,e)){
			c[id]++;return 1;
		}
	}
	return 0;
}

int main(){
	n=read,m=read,k=read;
	rep(i,1,m) a[i]=read;
	rep(i,1,n-1){
		int u=read,v=read;
		g[u].push_back({v,i});
		g[v].push_back({u,i});
	}
	rep(i,1,m-1) dfs(a[i],-1,a[i+1]);
	int sum=0;
	rep(i,1,n-1) sum+=c[i];
	if((sum+k)%2||(sum+k)<0){
		puts("0");return 0;
	}
	dp[0]=1;
	for(int i=1;i<=n-1;i++)
		for(int j=1e5;j>=c[i];j--)
			dp[j]=(dp[j]+dp[j-c[i]])%mod;
	cout<<dp[(sum+k)/2];
	
	
	
	
	
	return 0;
}

你可能感兴趣的:(#,ACM-图论/数据结构,#,ACM-计算几何/思维/构造,#,ACM-数论/动态规划,动态规划)