2 条题解

  • 0
    @ 2026-7-4 12:00:08

    #include <cstdio>
    #include <vector>
    using namespace std;
    const int M = 100005;
    const int MOD = 1e9+7;
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,d,f[M],g[M],g0[M],g1[M],cnt[M];vector<int> G[M];
    struct mat
    {
    	int a[2][2];
    	mat() {a[0][0]=a[1][0]=a[0][1]=a[1][1]=0;}
    	mat operator * (const mat &b) const
    	{
    		mat r;
    		for(int i=0;i<2;i++)
    		for(int j=0;j<2;j++)
    		for(int k=0;k<2;k++)
    			r.a[i][k]=(r.a[i][k]+a[i][j]*b.a[j][k])%MOD;
    		return r;
    	}
    }A,F;
    void dfs1(int u,int fa)
    {
    	cnt[u]=f[u]=g0[u]=g1[u]=g[u]=0;
    	for(int v:G[u]) if(v^fa)
    	{
    		dfs1(v,u);
    		if(!f[v]) cnt[u]++,g0[u]+=g[v];
    		else g1[u]+=g[v];
    	}
    	f[u]=(cnt[u]>0);
    	if(!f[u]) g[u]=g1[u]+1;
    	else if(cnt[u]==1) g[u]=g0[u];
    }
    void dfs2(int u,int fa)
    {
    	cnt[u]=f[u]=g0[u]=g1[u]=g[u]=0;
    	for(int v:G[u])
    	{
    		if(!f[v]) cnt[u]++,g0[u]+=g[v];
    		else g1[u]+=g[v];
    	}
    	f[u]=(cnt[u]>0);
    	if(!f[u]) g[u]=g1[u]+1;
    	else if(cnt[u]==1) g[u]=g0[u];
    	//
    	if(f[u]==1)
    	{
    		F.a[0][1]++;
    		A.a[0][0]=(A.a[0][0]+g[u])%MOD;
    		A.a[0][1]=(A.a[0][1]+n-g[u])%MOD;
    		A.a[1][1]=(A.a[1][1]+n)%MOD;
    	}
    	else
    	{
    		F.a[0][0]++;
    		A.a[0][1]=(A.a[0][1]+g[u])%MOD;
    		A.a[0][0]=(A.a[0][0]+n-g[u])%MOD;
    		A.a[1][0]=(A.a[1][0]+n)%MOD;
    	}
    	//
    	int tf=f[u],tg=g[u],tc=cnt[u];
    	for(int v:G[u]) if(v^fa)
    	{
    		if(!f[v])
    		{
    			if(cnt[u]==1)
    				cnt[u]=0,g[u]=g1[u]+1,f[u]=0;
    			else//f[u]=1;
    			{
    				cnt[u]--;
    				g[u]=(cnt[u]==1)?g0[u]-g[v]:0;
    			}
    		}
    		else if(!f[u]) g[u]=g1[u]-g[v]+1;
    		dfs2(v,u);
    		f[u]=tf;g[u]=tg;cnt[u]=tc;
    	}
    }
    signed main()
    {
    	n=read();d=read()-1;
    	for(int i=1;i<n;i++)
    	{
    		int u=read(),v=read();
    		G[u].push_back(v);
    		G[v].push_back(u);
    	}
    	dfs1(1,0);dfs2(1,0);
    	while(d>0) {if(d&1) F=F*A;A=A*A;d>>=1;}
    	int ans=g[1]*F.a[0][0]%MOD;
    	if(f[1]) ans=(n*(F.a[0][0]+F.a[0][1])-ans)%MOD;
    	printf("%lld\n",(ans+MOD)%MOD);
    }
    
    
    • 0
      @ 2025-12-14 0:14:04

      E97 换根DP+矩阵加速 P6803 [CEOI 2020] 星际迷航

      // 换根DP+矩阵加速 O(n+logD)
      #include <bits/stdc++.h>
      using namespace std;
      
      typedef long long LL;
      const int N=100005,M=1e9+7;
      vector<int> e[N];
      int n; LL D,m,ans;
      int f[N],r[N],s[N],c[N][2];
      
      void dfs(int x,int fa){
        for(int y:e[x]){
          if(y==fa) continue;
          dfs(y,x);
          s[x]+=!f[y]; //败点儿子的数量
          c[x][f[y]]+=r[y]; //可逆点的数量
        }
        f[x]=(s[x]>0); //若有败点儿子 则x为胜点
        if(s[x]==0) r[x]=c[x][1]+1; //没有败点儿子
        else if(s[x]==1) r[x]=c[x][0]; //只有一个败点儿子
        else r[x]=0; //有多个败点儿子
      }
      void dfs2(int x,int fa){
        if(f[x]==0) ++m;
        for(int y:e[x]){
          if(y==fa) continue;
          int fx=f[x],rx=r[x],sx=s[x],c0=c[x][0],c1=c[x][1];
          
          s[x]-=!f[y]; //去掉y的贡献
          c[x][f[y]]-=r[y];
          f[x]=(s[x]>0);
          if(s[x]==0) r[x]=c[x][1]+1;
          else if(s[x]==1) r[x]=c[x][0];
          else r[x]=0;
          s[y]+=!f[x]; //加上x的贡献
          c[y][f[x]]+=r[x];
          f[y]|=!f[x];
          if(s[y]==0) r[y]=c[y][1]+1;    
          else if(s[y]==1) r[y]=c[y][0];
          else r[y]=0;
          
          dfs2(y,x);
          f[x]=fx,r[x]=rx,s[x]=sx,c[x][0]=c0,c[x][1]=c1;
        }
      }
      
      struct mat{
        LL a[2][2];
        mat(){memset(a,0,sizeof a);}
        mat operator*(const mat &x){
          mat t;
          for(int i=0;i<2;i++)
          for(int j=0;j<2;j++)
          for(int k=0;k<2;k++)
            t.a[i][j]=(t.a[i][j]+a[i][k]*x.a[k][j])%M;
          return t;
        }  
      }F,A;
      void qpow(LL n){
        while(n){
          if(n&1) F=A*F;
          A=A*A;
          n>>=1;
        }
      }
      void add(LL &a,LL b){a=(a+b)%M;}
      int main(){
        scanf("%d%lld",&n,&D);
        for(int i=1,x,y;i<n;i++){
          scanf("%d%d",&x,&y);
          e[x].push_back(y),e[y].push_back(x);
        }
        dfs(1,0);
        dfs2(1,0); //换根DP
        
        for(int i=1;i<=n;i++){
          if(f[i]==0){
            add(A.a[0][0],n-r[i]);
            add(A.a[0][1],n);
            add(A.a[1][0],r[i]);
          } 
          else{
            add(A.a[0][0],r[i]);
            add(A.a[1][0],n-r[i]);
            add(A.a[1][1],n);
          }
        }
        F.a[0][0]=m,F.a[1][0]=n-m;
        qpow(D-1); //矩阵加速
        
        if(f[1]==0) ans=r[1]*F.a[0][0]%M;
        else ans=((n-r[1])*F.a[0][0]+n*F.a[1][0])%M;
        printf("%d\n",ans);
      }
      
      • 1

      E97 换根DP+矩阵加速「CEOI2020」星际迷航

      信息

      ID
      2411
      时间
      1000ms
      内存
      256MiB
      难度
      10
      标签
      递交数
      2
      已通过
      1
      上传者