bzoj 2314: 士兵的放置

Description


八中有N个房间和N-1双向通道,任意两个房间均可到达.现在出了一件极BT的事,就是八中开始闹鬼了。老大决定加强安保,现在如果在某个房间中放一个士兵,则这个房间以及所有与这个房间相连的房间都会被控制.现在

老大想知道至少要多少士兵可以控制所有房间.以及有多少种不同的方案数. 

Input

 

第一行一个数字N,代表有N个房间,房间编号从1开始到N.N<=500000,下面将有N-1行,每行两个数,代表这两个房间相连. 

Output

第一行输出至少有多少个士兵才可以控制所有房间第二行输出有多少种方案数,方案数会比较大,输出除以1032992941的余数吧. 

Sample Input

6
1 2
1 3
1 5
1 4
5 6

Sample Output

2
2


HINT

第一种方案是将士兵放在1号房间及6号房间 

第二种方案是将士兵放在1号房间及5号房间 


是的这题可以用树DP做。

0 1 2分别表示被子节点保护 自己放 不被保护

然后转移用乘法原理加法原理乱搞搞就可以了

记得分析清楚每种方法造成的方案数

以及。。我写的在bzoj上爆栈了= =大概是局部变量用太多?所以我特判了下一条链的情况【反正想卡还是随便卡】

各种手滑所以写了好久

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct line
{
     int s,t;
     int next;
}a[1000001];
int head[500001];
int edge;
inline void add(int s,int t)
{
	 a[edge].next=head[s];
     head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
}
long long f[500001][3];
long long fx[500001][3];
long long mod=1032992941;
bool v[500001];
int fa[500001];
inline long long power(long long x,int y)
{
	 long long tx=1;
     while(y!=0)
     {
          if(y%2==1)
               tx=(tx*x)%mod;
          x=(x*x)%mod;
          y=y/2;
     }
     return tx;
}
inline void trdp1(int d)
{
	 v[d]=true;
	 fx[d][2]=1;
	 fx[d][1]=1;
	 fx[d][0]=1;
     int i;
     bool flag=false;
     long long minx0=1,minx1=1,sx=1;
     int minx=2100000000;
     int st=0;
     for(i=head[d];i!=0;i=a[i].next)
     {
     	  int t=a[i].t;
          if(!v[t])
          {
          	   fa[t]=d;
               trdp1(t);
               if(f[t][1]<=f[t][0]||f[t][0]==0)
               {
                    f[d][0]+=f[t][1];
                    if(f[t][1]==f[t][0])
                    {
                         minx=min(minx,0);
                         fx[d][0]=(fx[d][0]*(fx[t][0]+fx[t][1]))%mod;
                         minx1=(minx1*(fx[t][0]+fx[t][1]))%mod;
                         minx0=(minx0*fx[t][0])%mod;
                    }
                    else
                    {
                         minx=-1;
                         fx[d][0]=(fx[d][0]*fx[t][1])%mod;
                    }
                    flag=true;
               }
               else
               {
                    f[d][0]+=f[t][0];
                    fx[d][0]=(fx[d][0]*fx[t][0])%mod;
                    sx=(sx*fx[t][0])%mod;
                    st++;
               }

               
               
               f[d][1]+=min(min(f[t][0],f[t][1]),f[t][2]);
               long long xtx=0;
               if(f[t][1]<=f[t][2])
               {
                    xtx+=fx[t][1];
                    if(f[t][1]==f[t][2])
                         xtx+=fx[t][2];
               }
               else
                    xtx+=fx[t][2];
               fx[d][1]=(fx[d][1]*xtx)%mod;
               
               xtx=f[t][0]>0?f[t][0]:2100000000;
               if(xtx<f[t][1])
               {
                    f[d][2]+=xtx;
                    fx[d][2]=(fx[d][2]*fx[t][0])%mod;
               }
               else if(xtx==f[t][1])
               {
                    f[d][2]+=xtx;
                    fx[d][2]=(fx[d][2]*(fx[t][0]+fx[t][1]))%mod;
               }
               else
               {
                    f[d][2]+=f[t][1];
                    fx[d][2]=(fx[d][2]*fx[t][1])%mod;
               }
          }
     }
	 if(!flag&&st!=0)
     {
          f[d][0]++;
          fx[d][0]=(fx[d][0]*power(sx,mod-2))%mod;
          long long s=0;
          for(i=head[d];i!=0;i=a[i].next)
          {
               int t=a[i].t;
               if(t==fa[d])
                    continue;
               s=(s+((sx*power(fx[t][0],mod-2))%mod)*fx[t][1]%mod)%mod;
          }
          fx[d][0]=(fx[d][0]*s)%mod;
     }
     else if(minx==0)
     {
          fx[d][0]=(fx[d][0]*power(minx1,mod-2))%mod;
          long long xtx=minx1-minx0;
          while(xtx<0)
               xtx+=mod;
          fx[d][0]=(fx[d][0]*xtx)%mod;
     }
     f[d][1]++;
}
int edg[500001];
int main()
{
	 freopen("lamps.in","r",stdin);
	 freopen("lamps.out","w",stdout);
     int n;
     scanf("%d",&n);
     int i;
     int s,t;
     bool flag=true;
     for(i=1;i<=n-1;i++)
     {
          scanf("%d%d",&s,&t);
          edge++;
          add(s,t);
          edge++;
          add(t,s);
          edg[s]++;
          edg[t]++;
          if(edg[s]>2||edg[t]>2)
               flag=false;
     }
     if(flag)
     {
     	  int xt=(n+1)/3;
          printf("%d\n%d\n",xt,xt+1);
          return 0;
     }
     memset(v,false,sizeof(v));
     trdp1(1);
  /*   for(i=1;i<=n;i++)
          printf("%d:%I64d %I64d %I64d\n",i,f[i][0],f[i][1],f[i][2]);
     printf("\n");
     for(i=1;i<=n;i++)
          printf("%d:%I64d %I64d %I64d\n",i,fx[i][0],fx[i][1],fx[i][2]);*/
     printf("%lld\n",min(f[1][0],f[1][1]));
     if(f[1][0]==f[1][1])
          printf("%lld\n",(fx[1][0]+fx[1][1])%mod);
     else if(f[1][1]<f[1][0]||f[1][0]==0)
          printf("%lld\n",fx[1][1]);
     else if(f[1][0]<f[1][1])
          printf("%lld\n",fx[1][0]);
     return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值