BZOJ 1063--道路設計(樹形DP)
看了題解才會。。。妙不可言的樹形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)