码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 1063--道路设计(树形DP)

时间:2017-10-29 20:18:02      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:char   http   遍历   链接   define   int   一个   getchar   algo   

    看了题解才会。。。妙不可言的树形DP。。。

题目链接:

    http://www.lydsy.com/JudgeOnline/problem.php?id=1063 

Solution

    设 dp [ i ] [ j ] [ k ] 表示以 i 为根的子树中,最大不便利值为 j ,i 向儿子连了 k 条铁路(k=0,1,2)的方案数

    根据树链剖分的思想:在节点 u 和节点 v 之间最多有 log2 ( n ) 条轻链,最多有log2 ( n ) 条重链。

    那么只要全连轻链就可以使最大不便利值不大于 log2 ( n ) 。。。。所以 j 的值范围一定不大于 log2 ( n )

    然后是状态转移:

      假设当前节点为 x ,对于其中一个子节点 v 

      设 s1 为 x 不向 v 连边的状态数,s2 为x向 v 连边的状态数。。那么s1和s2都是能算的。。

      s1 = dp [ v ] [ j - 1 ] [ 0 ] + dp [ v ] [ j - 1 ] [ 1 ] +  dp [ v ] [ j - 1 ] [ 2 ] ;    s1 = dp [ v ] [ j ] [ 0 ] + dp [ v ] [ j ] [ 1 ] ;

      于是:

        dp [ x ] [ j ] [ 2 ] = dp [ x ] [ j ] [ 2 ] * s1 + dp [ x ] [ j ] [ 1 ] * s2;

        dp [ x ] [ j ] [ 1 ] = dp [ x ] [ j ] [ 1 ] * s1 + dp [ x ] [ j ] [ 0 ] * s2;

        dp [ x ] [ j ] [ 0 ] = dp [ x ] [ j ] [ 0 ] * s1;

    对于无解的状态:DP的时候给经过的点做标记,最后遍历一遍,有未标记的点就是无解。。。

 

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define Maxans 17
#define N 100050
#define LL long long
using namespace std;
inline int Read(){
    int 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;
}
int n,m,Q,cnt=0;
int hed[N];
bool vis[N];
LL dp[N][20][5];
struct edge{
	int r,nxt;
}e[N<<1];
void insert(int u,int v){
	cnt++;e[cnt].r=v;e[cnt].nxt=hed[u];hed[u]=cnt;
	cnt++;e[cnt].r=u;e[cnt].nxt=hed[v];hed[v]=cnt;
}
LL mod(LL x){
	if( !x ) return x;
	if( !(x%Q) ) return Q;
	return x%Q;
}
void Tree_DP(int x,int fa){
	vis[x]=1;
	LL s1,s2;
	for(int j=0;j<=Maxans;j++) dp[x][j][0]=1;
	for(int i=hed[x];i;i=e[i].nxt)
		if(e[i].r!=fa){
			Tree_DP(e[i].r,x);
			for(int j=0;j<=Maxans;j++){
				if(j) s1=mod(dp[e[i].r][j-1][0]+dp[e[i].r][j-1][1]+dp[e[i].r][j-1][2]);
				else s1=0;
				s2=mod(dp[e[i].r][j][0]+dp[e[i].r][j][1]);
				dp[x][j][2]=mod(mod(dp[x][j][2]*s1)+mod(dp[x][j][1]*s2));
				dp[x][j][1]=mod(mod(dp[x][j][1]*s1)+mod(dp[x][j][0]*s2));
				dp[x][j][0]=mod(dp[x][j][0]*s1);
			}
		}
}
int main(){
	int u,v;
	n=Read();m=Read();Q=Read();
	for(int i=1;i<=m;i++){
		u=Read();v=Read();
		insert(u,v);
	}
	Tree_DP(1,0);
	for(int i=1;i<=n;i++)
		if(!vis[i]){
			printf("-1\n-1\n");
			return 0;
		}
	for(int j=0;j<=Maxans;j++)
		if(dp[1][j][0]+dp[1][j][1]+dp[1][j][2]){
			printf("%d\n%lld\n",j,(dp[1][j][0]+dp[1][j][1]+dp[1][j][2])%Q);
			return 0;
		}
}

  

  

This passage is made by Iscream-2001.

 

BZOJ 1063--道路设计(树形DP)

标签:char   http   遍历   链接   define   int   一个   getchar   algo   

原文地址:http://www.cnblogs.com/Yuigahama/p/7750805.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!