2013ACM/ICPC亚洲区南京站现场赛-HDU4809(树形DP)
为了这个题解第一次写东西。。(我只是来膜拜爱看touhou的出题人的)..
首先以为对称性质。。我们求出露琪诺的魔法值的期望就可以了。。之后乘以3就是答案。。(话说她那么笨。。能算出来么。。⑨⑨⑨⑨⑨⑨)
用dp表示方法数。。。
首先状态如此表示: 设dp(i,j,k)其中i代表节点的标号。。j代表状态(就像官方题解一样..0表示这个颜色不选,1代表选而且和子节点形成的联通块的节点数是奇数,2代表偶数)。。。k代表x-y的值。。
这样的话。。递推方程就能推咯。。然后慢慢把子节点dfs出来后加到根节点上面比如u是跟。v是儿子的话。。那么
dp[u][0][val] = dp[u][0][x]*dp[v][0][y] + dp[u][0][x]*dp[v][1][y-1] + dp[u][0][x]*dp[v][2][y+1] 。。。。。。。。。。。。。。(x+y = val)
dp[u][1][val] = dp[u][1][x]*dp[v][0][y] + dp[u][1][x]*dp[u][2][y] + dp[u][2][x]*dp[v][1][y]
dp[u][1][val] = dp[u][2][x]*dp[v][0][y] + dp[u][1][x]*dp[u][1][y] + dp[u][2][x]*dp[v][2][y]
至此。。这道题目基本就可以解决了。。其实还是有一些细节的(为什么有人跑的那么快。。我的却那么慢。。果然还是我太水了。。)
1 #include <iostream> //我是沙茶....今天又写搓了。。 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <climits> 7 #include <ctime> 8 #include <cmath> 9 #include <set> 10 #include <map> 11 #include <string> 12 #define MAX(a,b) ((a)>(b)?(a):(b)) 13 #define MIN(a,b) ((a)<(b)?(a):(b)) 14 #define abs(x) ((x)>0?(x):(-(x))) 15 #define FOR(i,a,b) for(int i = (a);i<=(b);i++) 16 #define FORD(i,a,b) for(int i = (a);i>=(b);i--) 17 #define REP(i,n) for(int i = 0;i<(n);i++) 18 #define rst(x,k) memset(x,k,sizeof(x)) 19 #define lowbit(x) ((x)&(-(x))) 20 #define h(x) (1<<(x)) 21 #define lson (ind<<1) 22 #define rson (ind<<1|1) 23 #define eps 1e-6 24 #define maxn 480 25 #define INF 1000000000 26 #define mod 1000000007LL 27 #define base 160 28 #define link fsafsdfas 29 using namespace std; 30 typedef long long LL; 31 struct node{ 32 int t,nxt; 33 }edge[maxn<<1]; 34 int headline[maxn],E; 35 void add(int f,int t){ 36 edge[E].t = t; 37 edge[E].nxt = headline[f]; 38 headline[f] = E++; 39 } 40 LL dp[310][3][480]; 41 LL tt[310][3][480]; 42 int n; 43 int high[310],low[310]; 44 int up,down; 45 void dfs(int u,int fa){ 46 dp[u][0][base] = 2; 47 dp[u][1][base] = 1; 48 high[u] = low[u] = 0; 49 for(int i = headline[u];~i;i = edge[i].nxt){ 50 int v = edge[i].t; if(v == fa)continue; 51 dfs(v,u);rst(tt[u],0); 52 FOR(p,low[u],high[u]){ //这种优化不太好。。如果谁有更快的优化方法求给蒟蒻说一下哈。。 53 FOR(q,low[v]-1,high[v]+1){ 54 if((p+q > n) || (p+q < (-n)/2-2))continue; 55 tt[u][0][p+q+base] += dp[u][0][p+base]*dp[v][0][q+base] + dp[u][0][p+base]*dp[v][1][q+base-1] + dp[u][0][p+base]*dp[v][2][q+base+1]; 56 tt[u][1][p+q+base] += dp[u][1][p+base]*dp[v][0][q+base] + dp[u][1][p+base]*dp[v][2][q+base] + dp[u][2][p+base]*dp[v][1][q+base]; 57 tt[u][2][p+q+base] += dp[u][1][p+base]*dp[v][1][q+base] + dp[u][2][p+base]*dp[v][0][q+base] + dp[u][2][p+base]*dp[v][2][q+base]; 58 tt[u][0][p+q+base] %= mod; if(tt[u][0][p+q+base] && p+q > high[u]) high[u] = p+q; if(tt[u][0][p+q+base] && p+q < low[u])low[u] = p+q; 59 tt[u][1][p+q+base] %= mod; if(tt[u][1][p+q+base] && p+q > high[u]) high[u] = p+q; if(tt[u][1][p+q+base] && p+q < low[u])low[u] = p+q; 60 tt[u][2][p+q+base] %= mod; if(tt[u][2][p+q+base] && p+q > high[u]) high[u] = p+q; if(tt[u][2][p+q+base] && p+q < low[u])low[u] = p+q; 61 } 62 } 63 FOR(j,low[u],high[u]){ 64 dp[u][0][j+base] = tt[u][0][j+base]; 65 dp[u][1][j+base] = tt[u][1][j+base]; 66 dp[u][2][j+base] = tt[u][2][j+base]; 67 } 68 } 69 } 70 71 void solve(){ 72 rst(headline,-1); E = 0; 73 rst(dp,0); 74 REP(i,n-1){ 75 int a,b; scanf("%d%d",&a,&b); 76 add(a,b); add(b,a); 77 } 78 up = n; down = -n/2-1; 79 dfs(1,0); 80 LL ans = 0; 81 FOR(i,-1,up){ 82 ans += dp[1][0][i+base]*(MAX(i,0))%mod; 83 ans += dp[1][1][i+base]*(MAX(i+1,0))%mod; 84 ans += dp[1][2][i+base]*(MAX(i-1,0))%mod; 85 ans %= mod; 86 } 87 printf("%I64d\n",ans*3%mod); 88 } 89 int main(void){ 90 while(EOF != scanf("%d",&n))solve(); 91 return 0; 92 }