[CEOI2020]星际迷航 题解

博弈+换根 dp+矩阵快速幂优化 dp

Statement

P6803 [CEOI2020]星际迷航 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Solution

看到 \(D\le 10^{18}\) ,知道这道题最后大概是需要一个矩阵快速幂

所以先考虑 \(D=1\) 的情况,容易发现对于一个必胜态而言,无论接一个都不会改变状态,对于一个必败态,只有接上一个比败态会改变状态

容易一遍 dfs 求出每一个节点的状态 \(g[u]=0/1\) ,必败/胜。令 \(lose\) 表示必败态个数

\(f[u]\) 表示 \(u\) 的子树中,有多少个点在接入一个必败态后会使得 \(u\) 的状态改变

所以,若 \(g[1]=0\)\(ans=f[1]\times lose\) ,也就是对于那些可以把 \(1\) 扳正的位置,给他配一个 \(lose\)

\(g[1]=1\) ,$ans=n\times (n-lose)+lose\times(n-f[1]) $ ,现在不需要对 \(1\) 更改,所以对于 \((n-lose)\) 个必胜点,随便接啥都可以,然后不能给那 \(f[1]\) 个点接败点

现在考虑扩展一下,\(D=2\) 咋做

发现只需要把怎么把第二第三棵树怎么合并一下然后当成 \(D=2\)

发现我们算答案其实需求的是 \(lose\)\((n-lose)\) ,其他的量不会因为 \(D\) 的改变而改变

也就是说,现在需要求出的是 \(lose\)\(win\) 的方案数,设为 \(l\)\(w\) ,也就是第三棵树往第二棵树上接,第二棵树中败点个数总和 和 胜点个数总和

求出后,答案依然是 \([g[1]==0] f[1]\times l+[g[1]==1]n\times w+[g[1]==1]l\times(n-f[1])\)

为了计算 \(l,w\),发现好像需要每一个点的 \(f\) ,可以借助换根 \(dp\) 求出

所以,当 \(D=2\) 时,

\[l=\sum[g[i]=0](n-f[i])\times lose+\sum[g[i]=0]n\times(n-lose)+\sum[g[i]=1] f[i]\times lose\\ w=\sum[g[i]=1](n-f[i])\times lose+\sum[g[i]=1]n\times(n-lose)+\sum[g[i]=0]f[i]\times lose \]

容易注意到其实 \(lose/win\)\(l/w\) 的本质是一样的,我们把上面的转移写成矩阵的形式

\[\left[\begin{array}{cc|r}l^{\prime}&w^{\prime}\end{array}\right] \left[\begin{array}{cc|r}\sum[g=0](n-f)+[g=1]f&\sum[g=1](n-f)+[g=0]f\\\sum [g=0]n&\sum [g=1]n\end{array}\right]=\left[\begin{array}{cc|r}l&w\end{array}\right] \]

最开始是 \([lose,n-lose]\)

很对,复杂度 \(O(n\log K+n)\)

换根 \(dp\) 有一点小细节

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+5;
const int mod = 1e9+7;

char buf[1<<23],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
ll read(){
    ll s=0,w=1; char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')w=-1; ch=getchar();}
    while(isdigit(ch))s=s*10+(ch^48),ch=getchar();
    return s*w;
}

struct matrix{
    int a[2][2];
    matrix(bool fg=false){
        memset(a,0,sizeof(a));
        if(fg)a[0][0]=a[1][1]=1;
    }
    matrix operator*(const matrix&rhs)const{
        matrix res;
        for(int i=0;i<2;++i)for(int j=0;j<2;++j)
            res.a[i][j]=(1ll*a[i][0]*rhs.a[0][j]%mod+1ll*a[i][1]*rhs.a[1][j]%mod)%mod;
        return res;
    }
}p,t;
vector<int>Edge[N];
int g[N],s0[N],f[N],sf[N][2];
int g2[N],f2[N];
int n,lose;
ll k;

void dfs1(int u,int fath){
    for(auto v:Edge[u])if(v^fath){
        dfs1(v,u);
        s0[u]+=!g[v];
        sf[u][g[v]]+=f[v];
    }
    g[u]=s0[u]>0;
    if(s0[u]==1)f[u]=sf[u][0];
    else if(s0[u]==0)f[u]=sf[u][1]+1;
}
void dfs2(int u,int fath){
    lose+=!g[u],f2[u]=f[u],g2[u]=g[u];
    for(auto v:Edge[u])if(v^fath){
        int dpu=g[u],s0u=s0[u],ru=f[u],sru0=sf[u][0],sru1=sf[u][1];
        int dpv=g[v],s0v=s0[v],rv=f[v],srv0=sf[v][0],srv1=sf[v][1];

        s0[u]-=!g[v];
        sf[u][g[v]]-=f[v];
        g[u]=s0[u]>0;
        if(s0[u]==1)f[u]=sf[u][0];
        else if(s0[u]==0)f[u]=sf[u][1]+1;
        else f[u]=0;

        s0[v]+=!g[u];
        sf[v][g[u]]+=f[u];
        g[v]=s0[v]>0;
        if(s0[v]==1)f[v]=sf[v][0];
        else if(s0[v]==0)f[v]=sf[v][1]+1;
        else f[v]=0;
        
        dfs2(v,u);
        g[u]=dpu,s0[u]=s0u,f[u]=ru,sf[u][0]=sru0,sf[u][1]=sru1;
        g[v]=dpv,s0[v]=s0v,f[v]=rv,sf[v][0]=srv0,sf[v][1]=srv1;
    }
}
matrix ksm(matrix a,ll b){
    matrix res(1);
    while(b){
        if(b&1)res=res*a;
        a=a*a,b>>=1;
    }
    return res;
}

signed main(){
    n=read(),k=read();
    for(int i=1,u,v;i<n;++i)
        u=read(),v=read(),
        Edge[u].push_back(v),
        Edge[v].push_back(u);
    dfs1(1,0),dfs2(1,0);
    p.a[0][0]=lose,p.a[0][1]=n-lose;
    for(int i=1;i<=n;++i)
        if(g2[i]==0)
            (t.a[0][0]+=n-f2[i])%=mod,
            (t.a[0][1]+=f2[i])%=mod,
            (t.a[1][0]+=n)%=mod;
        else (t.a[0][0]+=f2[i])%=mod,
            (t.a[0][1]+=n-f2[i])%=mod,
            (t.a[1][1]+=n)%=mod;
    p=p*ksm(t,k-1);
    if(g[1])printf("%lld\n",(1ll*(n-f2[1])*p.a[0][0]%mod+1ll*n*p.a[0][1]%mod)%mod);
    else printf("%lld\n",1ll*f2[1]*p.a[0][0]%mod);
    return 0;
}
posted @ 2022-04-08 20:56  _Famiglistimo  阅读(101)  评论(0编辑  收藏  举报