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

bzoj2314: 士兵的放置(树形DP)

时间:2017-12-09 16:56:32      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:lock   eve   ora   algo   event   auto   long   zoj   void   

  0表示被父亲控制,1表示被儿子控制,2表示被自己控制。f表示最少士兵数,g表示方案数。

  转移贼难写,写了好久之后写不下去了,看了一眼题解,学习了。。。原来还可以这么搞

  比如求f[i][1]的时候,要在所有儿子里选一个儿子的f[to][2]来转移,这有一个非常巧妙的做法,那就是从自己转移...

  每次可以选择从f[i][1]+min(f[to][1], f[to][2])转移或者从f[i][0]+f[to][2]转移,并使得f[i][1]比f[i][0]先转移,这样的话相当于每次会从第一次取f[to][2]和已经取过f[to][2]转移,十分正确,非常好写...

  还要注意的是如果从f[i][0]转移,方案数得加上g[i][0]*g[to][2]。

技术分享图片
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define ll long long
#define MOD(x) ((x)>=mod?(x-mod):(x))
using namespace std;
const int maxn=500010, inf=1e9, mod=1032992941;
struct poi{int too, pre;}e[maxn<<1];
int n, x, y, tot;
int last[maxn], g[maxn][3], f[maxn][3];;
void read(int &k)
{
    int f=1; k=0; char c=getchar();
    while(c<0 || c>9) c==-&&(f=-1), c=getchar();
    while(c<=9 && c>=0) k=k*10+c-0, c=getchar();
    k*=f;   
} 
inline void add(int x, int y){e[++tot]=(poi){y, last[x]}; last[x]=tot;}
void dfs(int x, int fa)
{
    f[x][1]=maxn; f[x][2]=g[x][0]=g[x][1]=g[x][2]=1;
    for(int i=last[x], too;i;i=e[i].pre)
    if((too=e[i].too)!=fa)
    {
        dfs(too, x);
        ll tmpf=min(maxn, min(f[x][1]+min(f[too][1], f[too][2]), f[x][0]+f[too][2])), tmpg=0;
        if(f[x][1]+f[too][1]==tmpf) tmpg+=g[too][1];
        if(f[x][1]+f[too][2]==tmpf) tmpg+=g[too][2], tmpg=MOD(tmpg);
        f[x][1]=tmpf; g[x][1]=1ll*g[x][1]*tmpg%mod;
        if(f[x][0]+f[too][2]==tmpf) g[x][1]+=1ll*g[x][0]*g[too][2]%mod, g[x][1]=MOD(g[x][1]);
        f[x][0]+=f[too][1]; f[x][0]=min(maxn, f[x][0]); g[x][0]=1ll*g[x][0]*g[too][1]%mod;
        tmpf=min(f[too][0], min(f[too][1], f[too][2])); tmpg=0;
        if(f[too][0]==tmpf) tmpg+=g[too][0];
        if(f[too][1]==tmpf) tmpg+=g[too][1], tmpg=MOD(tmpg);
        if(f[too][2]==tmpf) tmpg+=g[too][2], tmpg=MOD(tmpg);
        f[x][2]+=tmpf; f[x][2]=min(maxn, f[x][2]); g[x][2]=1ll*g[x][2]*tmpg%mod;
    }
}
int main()
{
    read(n);
    for(int i=1;i<n;i++) read(x), read(y), add(x, y), add(y, x);
    dfs(1, 0); 
    if(f[1][1]<f[1][2]) printf("%d\n%d", f[1][1], g[1][1]);
    else if(f[1][1]>f[1][2]) printf("%d\n%d", f[1][2], g[1][2]);
    else printf("%d\n%d", f[1][1], MOD(g[1][1]+g[1][2]));
}
View Code

  明明答案不会爆int的。。。但是不开LL就WA,至今不明T T 神tm..f的不合法状态是inf加起来爆int了,判了一下之后终于能int过了,因为比LL快也跑到了rk10

  为了查这个我WA了一页...技术分享图片

 

bzoj2314: 士兵的放置(树形DP)

标签:lock   eve   ora   algo   event   auto   long   zoj   void   

原文地址:http://www.cnblogs.com/Sakits/p/8011626.html

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