1 条题解

  • 0
    @ 2025-8-24 22:43:54

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar abruce
    I won't feel lonely, nor will I be sorrowful... not before everything is buried.

    搬运于2025-08-24 22:43:54,当前版本为作者最后更新于2022-12-19 15:34:33,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    目前已改正为 O(n2)O(n^2),数据有可能之后会加强。

    在正解中,我们先求出 fu,kf_{u,k} 表示 uu 子树内进行了 kk 次操作的方案,树形背包即可,这部分 O(n2)O(n^2)。同时我们也解决了 k=1k=1x=1x=1
    考虑到钦定 xx 操作位置会影响其所有祖先选择,可以想到把祖先和他们的其它子树分开,但这样具有后效性(因为难以保证 uu 的子树的操作都在 uu 之前),所以我们考虑从根进行二次 dp。
    首先,我们把 11xx 这条链称为“茎”,和题目描述一样。
    gu,kg_{u,k} 为当前茎从根选到了 uu,剩余 kk 操作给茎 uu 后面的点留着,这些操作有相对顺序但并未被实际放在操作序列的某一个位置上。最终答案就是 gx,k1g_{x,k-1} (强制钦定到达 xxkk 这个位置 dp 值不能拷贝过来即可)。
    考虑转移,当从 fafa 转移到 uu 时,我们先考虑 uu 选不选。如果不选,直接拷贝,否则设它和父亲之间填了 pp 个操作,从 gfa,kg_{fa,k} 转移过来的话,那么操作序列就必须按顺序填 fafa 给他留的 pp 个操作。所以转移到 gu,kpg_{u,k-p},可以通过一个前缀和优化做到单次 O(n)O(n),总共 O(n2)O(n^2)
    接下来我们考虑把 uu 不在茎上的子树的操作填进去,不难发现这些操作都是给后面留的,于是背包一下即可。复杂度分析可以看做一棵以 xx 为根的树做树形背包,复杂度 O(n2)O(n^2)
    综上,我们在 O(n2)O(n^2) 的时间通过了本题。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int read() {
        int x=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9') {
            if(c=='-')f=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
        return x*f;
    }
    namespace tokidosaya {
        const int maxn=505,mod=1e9+7;
        struct edge {
            int next,to;
        } e[maxn*2];
        int h[maxn],cnt,n,k,X,d[maxn],ff[maxn],siz[maxn],now,zc[maxn],o;
        ll f[maxn][maxn],ans,fac[maxn],inv[maxn],g[2][maxn],w[maxn];
        void addedge(int x,int y) {
            e[++cnt].next=h[x],e[cnt].to=y,h[x]=cnt;
        }
        ll qpow(ll x,int y) {
            ll w=1;
            while(y) {
                if(y&1)w=w*x%mod;
                x=x*x%mod,y>>=1;
            }
            return w;
        }
        ll C(int x,int y) {
            if(y>x||y<0)return 0;
            return fac[x]*inv[x-y]%mod*inv[y]%mod;
        }
        void dfs(int u,int fa) {
            ff[u]=fa,f[u][0]=1;
            for(int i=h[u]; i; i=e[i].next) {
                int v=e[i].to;
                if(v==fa)continue;
                dfs(v,u);
                for(int j=siz[u]; j>=0; j--)
                    for(int k=siz[v]; k; k--)f[u][j+k]=(f[u][j+k]+f[u][j]*f[v][k]%mod*C(j+k,k))%mod;
                siz[u]+=siz[v];
            }
            for(int i=siz[u]; i>=0; i--)f[u][i+1]=(f[u][i+1]+f[u][i])%mod;
            siz[u]++;
        }
        int getw(int u) {
            int nc=0;
            memset(w,0,sizeof(w)),w[0]=1;
            for(int i=h[u]; i; i=e[i].next) {
                int v=e[i].to;
                if(d[v])continue;
                for(int j=nc; j>=0; j--)
                    for(int k=siz[v]; k; k--)w[j+k]=(w[j+k]+w[j]*f[v][k]%mod*C(j+k,k))%mod;
                nc+=siz[v];
            }
            return nc;
        }//这个相当于把不在茎上的子树合并进去
        int main() {
            int x,y;
            n=read(),k=read(),X=read(),fac[0]=1;
            for(int i=1; i<=n; i++)fac[i]=fac[i-1]*i%mod;
            inv[n]=qpow(fac[n],mod-2);
            for(int i=n; i; i--)inv[i-1]=inv[i]*i%mod;
            for(int i=1; i<n; i++) {
                x=read(),y=read();
                addedge(x,y),addedge(y,x);
            }
            dfs(1,0),x=X;
            while(x)d[x]=1,zc[++o]=x,x=ff[x];
            reverse(zc+1,zc+o+1),getw(1);
            for(int i=0; i<n; i++)g[1][i]=w[i];
            for(int i=2; i<=o; i++) {
                int now=i&1,lst=now^1,u=zc[i],nc=getw(u);
                memcpy(g[now],g[lst],sizeof(g[now]));
                ll sum=0;
                for(int j=n-1; j>=0; j--) {
                    sum=(sum+g[now][j])%mod;
                    if(i==o)g[now][j]=0;
                    g[now][j]=(g[now][j]+sum)%mod;
                }
                for(int j=n-1; j>=0; j--)
                    if(g[lst][j])for(int k=nc; k; k--)g[now][j+k]=(g[now][j+k]+g[now][j]*w[k]%mod*C(j+k,k))%mod;
            }
            printf("%lld",g[o&1][k-1]);
            return 0;
        }
    }
    int main() {
        return tokidosaya::main();
    }
    
    
    • 1

    信息

    ID
    8045
    时间
    1000ms
    内存
    128MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者