LOJ #3044. 「ZJOI2019」Minimax 搜索 动态DP+概率

神仙 DP.
可以求解 $1$ 号点的答案 $val(1)=w$.
假设所选的 $S$ 集合包含 $w$,那么答案一定为 $1$.
令叶子节点个数为 $m$,则有 $2^{m-1}$ 个集合的答案为 $1$.
假设当前修改代价为 $i$,想让根节点的答案改变.
最优改变方式有两种:
1.将小于 $w$ 的改成 $w+1$,其余不变.
2.将大于 $w$ 的改成 $w-1$,其余不变.
我们发现遵循 $1,2$ 改法一定是最优的.
令 $f_{x},g_{x}$ 分别表示上述 $1,2$.
然后 $f_{x},g_{x}$ 改的集合是没有交集的.
但是可能会出现 $f_{x}$ 改了 $A$,没改 $B$,而 $g_{x}$ 改了 $B$ 而没改 $A$.
直接将 $f_{x},g_{x}$ 相加可能会算重.
所以将 $f_{x},g_{x}$ 定义为概率,根节点的答案就是 $2^m(f_{x}+g_{x}-f_{x}g_{x})$
$f_{x}$ 与 $g_{x}$ 的转移的话按照层数分奇偶讨论一下即可.
剩下的东西就用动态 DP 优化吧.
感觉这题能拿 $70pts$ 就不错了吧......

#include <bits/stdc++.h>   
#define ll long long 
#define N 300008    
#define mod 998244353 
#define setIO(s) freopen(s".in","r",stdin)  
using namespace std;     

int si[N],an[N],n,W,det,CUR;              
int dep[N],hd[N],to[N<<1],nex[N<<1],leaf[N],fa[N],inv[N],edges;    

void add(int u,int v) 
{ 
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;   
}  

inline int qpow(int x,int y) 
{
    int tmp=1;   
    for(;y;y>>=1,x=(ll)x*x%mod)  
        if(y&1) tmp=(ll)tmp*x%mod;   
    return tmp;     
}
inline int INV(int x) { return qpow(x,mod-2); }

// 特殊数字处理    
struct spe
{   
    int x,y;   
    spe(int a=1,int b=0) { x=a,y=b; }                    
    spe operator*(const spe b) const 
    {     
        spe c;    
        c.x=(ll)x*b.x%mod;    
        c.y=y+b.y;       
        return c;    
    }      
    spe operator/(const spe b) const 
    {
        spe c;   
        c.x=(ll)x*INV(b.x)%mod;   
        c.y=y-b.y;      
        return c;    
    }   
    inline void modify(int v) 
    {
        if(v) x=v,y=0;      
        else x=1,y=1;     
    }      
    inline int val() { return y?0:x; }                      
}G[N],G1[N];          

// 矩阵乘法    
struct matrix
{
    int a[2][2];     
    matrix() { memset(a,0,sizeof(a)); }
    int *operator[](int x) { return a[x]; }                       
    matrix operator*(matrix b) const 
    {
        matrix c;     
        for(int i=0;i<2;++i) 
        {
            for(int j=0;j<2;++j) 
                for(int k=0;k<2;++k)    
                    (c[i][j]+=(ll)a[i][k]*b[k][j]%mod)%=mod; 
        }
        return c;     
    }
}tmp[N],F[N],F1[N],tmp1[N];           

// 动态树    
#define lson s[x].ch[0] 
#define rson s[x].ch[1]   

int sta[N];    
struct data { int ch[2],f,r; }s[N];      
inline int get(int x) { return s[s[x].f].ch[1]==x; }   
inline int isr(int x) { return s[s[x].f].ch[0]!=x&&s[s[x].f].ch[1]!=x; }

void pushup(int x) 
{   
    s[x].r=x;   
    // 叶节点特判   
    if(leaf[x])   
    {    
        F[x][0][0]=1,F[x][0][1]=F[x][1][1]=0;     
        F[x][1][0]=G[x].val();    
        F1[x][0][0]=1,F1[x][0][1]=F1[x][1][1]=0;   
        F1[x][1][0]=G1[x].val();    
        if(lson) 
        {
            F[x]=F[lson]*F[x];    
            F1[x]=F1[lson]*F1[x];    
        }
    }   
    else if(CUR==x) 
    {
        F[x][0][0]=1,F[x][0][1]=F[x][1][1]=0;
        F1[x][0][0]=1,F1[x][0][1]=F1[x][1][1]=0;         
        if(dep[x]%2==1) 
        {
            F[x][1][0]=(1-G[x].val()+mod)%mod;   
            F1[x][1][0]=G1[x].val();   
        }
        if(dep[x]%2==0) 
        {
            F[x][1][0]=G[x].val();   
            F1[x][1][0]=(1-G1[x].val()+mod)%mod;   
        }
        if(lson) F[x]=F[lson]*F[x],F1[x]=F1[lson]*F1[x];    
    }  
    else 
    { 
        F[x]=tmp[x];   
        F1[x]=tmp1[x];   
        if(lson) 
        {
            F[x]=F[lson]*F[x];     
            F1[x]=F1[lson]*F1[x];   
        }
        if(rson)
        {
            s[x].r=s[rson].r;    
            F[x]=F[x]*F[rson];     
            F1[x]=F1[x]*F1[rson];   
        }
    }
}          
void rotate(int x) 
{
    int old=s[x].f,fold=s[old].f,which=get(x); 
    if(!isr(old)) 
        s[fold].ch[s[fold].ch[1]==old]=x;      
    s[old].ch[which]=s[x].ch[which^1]; 
    if(s[old].ch[which]) 
        s[s[old].ch[which]].f=old;      
    s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold;   
    pushup(old),pushup(x);    
} 
void splay(int x) 
{
    int u=x,fa; 
    for(;!isr(u);u=s[u].f);
    CUR=s[u].r;            
    for(u=s[u].f;(fa=s[x].f)!=u;rotate(x))   
        if(s[fa].f!=u)   
            rotate(get(fa)==get(x)?fa:x);    
    CUR=0;    
}    
void Access(int x) 
{
    for(int y=0;x;y=x,x=s[x].f) 
    {
        splay(x);                   
        if(rson) 
        {     
            spe t,t2;    
            if(dep[x]%2==1) 
            {
                t.modify(1-F[rson][1][0]+mod);  
                t2.modify(F1[rson][1][0]); 
            }
            if(dep[x]%2==0) 
            {
                t.modify(F[rson][1][0]);    
                t2.modify(1-F1[rson][1][0]+mod);    
            }
            G[x]=G[x]*t;    
            G1[x]=G1[x]*t2;   
        }
        if(y) 
        {            
            spe t,t2;                 
            if(dep[x]%2==1) 
            {
                t.modify(1-F[y][1][0]+mod);   
                t2.modify(F1[y][1][0]); 
            }
            if(dep[x]%2==0) 
            {
                t.modify(F[y][1][0]);     
                t2.modify(1-F1[y][1][0]+mod); 
            }
            G[x]=G[x]/t;           
            G1[x]=G1[x]/t2;  
        }
        // 取 max        
        if(dep[x]%2==1) 
        {                
            tmp[x][1][1]=G[x].val();      
            tmp[x][1][0]=(1-G[x].val()+mod)%mod;       

            tmp1[x][1][1]=G1[x].val(); 
            tmp1[x][1][0]=0; 
        } 
        else 
        {   
            tmp[x][1][1]=G[x].val();    
            tmp[x][1][0]=0;  

            tmp1[x][1][1]=G1[x].val();  
            tmp1[x][1][0]=(1-G1[x].val()+mod)%mod;     
        }  
        rson=y;
        if(!y) CUR=x;    
        pushup(x),CUR=0;   
    }
}
#undef lson 
#undef rson  

void dfs(int x,int ff) 
{ 
    fa[x]=ff,dep[x]=dep[ff]+1,leaf[x]=1;         
    if(dep[x]%2==1) an[x]=-N; 
    else an[x]=N; 
    for(int i=hd[x];i;i=nex[i]) 
    {
        int y=to[i];   
        if(y==ff) continue;     
        leaf[x]=0,dfs(y,x),si[x]+=si[y];   
        if(dep[x]%2==1) 
            an[x]=max(an[x],an[y]);   
        else 
            an[x]=min(an[x],an[y]);   
    }     
    if(leaf[x]==1) si[x]=1,an[x]=x;    
} 

void dfs2(int x) 
{    
    s[x].f=fa[x];               
    G[x].modify(1);  
    G1[x].modify(1);          
    for(int i=hd[x];i;i=nex[i])  
    {
        int y=to[i]; 
        if(y==fa[x]) continue;   
        dfs2(y);        
        spe t,t2;    
        // 取 max   
        if(dep[x]%2==1) 
        {          
            t.modify((1-F[y][1][0]+mod)%mod);     
            t2.modify(F1[y][1][0]);  
            G[x]=G[x]*t;           
            G1[x]=G1[x]*t2;     
        } 
        // 取 min  
        else
        {         
            t.modify(F[y][1][0]);     
            t2.modify((1-F1[y][1][0]+mod)%mod);   
            G[x]=G[x]*t;   
            G1[x]=G1[x]*t2;    
        }
    }             
    if(leaf[x]) 
    {
        if(x==W) G[x].modify(0),G1[x].modify(0);  
        else 
        {
            if(x>W) 
            {    
                G[x].modify(1); 
                G1[x].modify(0);  
                if(x-det<W) G1[x].modify(inv[2]);     
            } 
            if(x<W) 
            {     
                G[x].modify(0);   
                if(x+det>W) G[x].modify(inv[2]);  
                G1[x].modify(1);      
            }
        }
    }  
    else
    { 
        tmp[x][0][0]=1;   
        tmp[x][0][1]=0;   
        tmp[x][1][1]=G[x].val();   

        tmp1[x][0][0]=1; 
        tmp1[x][0][1]=0; 
        tmp1[x][1][1]=G1[x].val(); 

        if(dep[x]%2==0) tmp[x][1][0]=0,tmp1[x][1][0]=(1-G1[x].val()+mod)%mod; 
        if(dep[x]%2==1) tmp[x][1][0]=(1-G[x].val()+mod)%mod,tmp1[x][1][0]=0;   
    }
    CUR=x,pushup(x),CUR=0;       
}

int Ans[N];  
int out[N];  

int main() 
{
    // setIO("input");      
    inv[0]=1;   
    for(int i=1;i<N;++i)  
        inv[i]=INV(i);   
    int L,R; 
    scanf("%d%d%d",&n,&L,&R);  
    for(int i=1;i<n;++i) 
    {
        int x,y;  
        scanf("%d%d",&x,&y);   
        add(x,y),add(y,x);  
    }
    dfs(1,0),W=an[1];  
    for(int i=W;i;i=fa[i]) --si[i];    
    det=1;   
    dfs2(1);      
    int co=qpow(2,si[1]);   
    for(det=1;det<n;++det) 
    {
        int p=W+1-det;         
        if(p>0&&leaf[p]&&p!=W) 
        {
            Access(p),splay(p);     
            G[p].modify(inv[2]);   
            pushup(p);     
        }
        int q=W-1+det;  
        if(q<=n&&leaf[q]&&q!=W) 
        {
            Access(q),splay(q);  
            G1[q].modify(inv[2]); 
            pushup(q); 
        }
        Access(1),splay(1);      

        Ans[det]=(ll)(F[1][1][0]+F1[1][1][0]-(ll)F[1][1][0]*F1[1][1][0]%mod+mod)%mod; 
        Ans[det]=(ll)Ans[det]*co%mod;    

        int cu=(det==1?co:0);   

        out[det]=(ll)(Ans[det]-Ans[det-1]+cu+mod)%mod;   

    }     
    out[n]=(ll)(co-Ans[n-1]+mod-1)%mod;  
    for(int i=L;i<=R;++i) printf("%d ",out[i]);    
    return 0; 
}

  

posted @ 2020-04-29 08:16  EM-LGH  阅读(212)  评论(0编辑  收藏  举报