zoukankan      html  css  js  c++  java
  • 【题解】Luogu P5291 [十二省联考2019]希望

    ytq鸽鸽出的题真是毒瘤

    原题传送门

    题目大意:

    有一棵有(n)个点的树,求有多少方案选(k)个联通块使得存在一个中心点(p),所有(k)个联通块中所有点到(p)的距离都(leq L)

    我们先从部分分考虑:

    算法1

    (2^{nk})枚举联通快判断是否可行

    期望得分:8pts

    代码就不给了

    引理1

    对于任意一个联通块,可能成为它的中心点的点组成的集合也是一个联通块。正确性显然

    • 推论

    这里作为(k)个联通块中心点的点组成的集合是一个联通块

    算法2

    枚举推论中中心点组成的集合,判断其他是否满足

    期望得分:16pts

    代码也不给了

    引理2

    注意到树上联通块中,点集为(S),边集为(E),有(|S|-|E|=1)。正确性显然

    这样我们就珂以对每个点、边单独考虑,通过容斥算出答案。设(f(x))表示(x)控制的联通块个数,(g(e))表示(e)两端点都控制的联通块个数,易知答案为

    [sum_{v in V}f(v)^k-sum_{e in E}g(e)^k ]

    算法3

    我们考虑dp,设(f_{i,j})表示(i)点子树中距离(i)不超过(j)且包含(i)的个数,(g_{i,j})表示(i)点子树外距离(i)不超过(j)且包含(i)的个数,转移如下:

    [f_{i,j}=prod_{v in son(i)}(f_{v,j-1}+1) ]

    [g_{i,j}=g_{fa_i,j-1}prod_{v in son(fa_i),v eq i}(f_{v,j-2}+1)+1 ]

    对于每个点(i),对答案的贡献为:

    [(f_{i,L}·g_{i,L})^k ]

    对于每条边(e)(设(v)为深度更深的点),对答案的贡献为:

    [-(f_{v,L-1}·(g_{v,L}-1))^k ]

    时间复杂度:(O(nL))

    期望得分:36pts

    算法4:

    对于(L=n)的测试点,第二维的限制没用了,去掉即可

    时间复杂度:(O(n))

    期望得分:结合算法3可得48pts

    算法5:

    对于链的情况,珂以手推一下dp的贡献,发现就是距离,算一下即可

    时间复杂度:(O(n))

    期望得分:结合算法4可得52pts

    这是暴力52pts的做法,代码如下,subtask1是算法3,subtask2是算法4,subtask3是算法5

    #include <bits/stdc++.h>
    #define mod 998244353
    #define N 100005
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    inline int power(register int a,register int b)
    {
        int res=1;
        while(b)
        {
            if(b&1)
                res=1ll*res*a%mod;
            a=1ll*a*a%mod;
            b>>=1;
        }
        return res;
    }
    struct egde{
        int to,next;
    }e[N<<2];
    int head[N<<1],cnt=0;
    inline void add(register int u,register int v)
    {
        e[++cnt]=(egde){v,head[u]};
        head[u]=cnt;
    }
    int n,m,k,ans;
    namespace subtask1{
        vector<int> f[N],g[N];
        inline void dfs1(register int x,register int fa)
        {
            for(register int i=head[x];i;i=e[i].next)
            {
                int v=e[i].to;
                if(v==fa)
                    continue;
                dfs1(v,x);
                for(register int j=1;j<=m;++j)
                    f[x][j]=1ll*f[x][j]*(f[v][j-1]+1)%mod;
            }
        }
        inline void dfs2(register int x,register int fa)
        {
            static int son[N],pre[N],suf[N];
            int cnt=0;
            for(register int i=head[x];i;i=e[i].next)
                if(e[i].to!=fa)
                    son[++cnt]=e[i].to;
            for(register int i=pre[0]=suf[cnt+1]=1;i<=m;++i)
            {
                if(i>=2)
                {
                    for(register int j=1;j<=cnt;++j)
                        pre[j]=1ll*pre[j-1]*(f[son[j]][i-2]+1)%mod;
                    for(register int j=cnt;j>=1;--j)
                        suf[j]=1ll*suf[j+1]*(f[son[j]][i-2]+1)%mod;
                }
                else
                {
                    for(register int j=1;j<=cnt;++j)
                        pre[j]=suf[j]=1;
                }
                for(register int j=1;j<=cnt;++j)
                    g[son[j]][i]=(1ll*g[x][i-1]*pre[j-1]%mod*suf[j+1]+1)%mod;
            }
            for(register int i=head[x];i;i=e[i].next)
            {
                int v=e[i].to;
                if(v==fa)
                    continue;
                ans=(ans+power(1ll*(g[v][m]-1)*f[v][m-1]%mod,k))%mod;
                dfs2(v,x);
            }
        }
        inline void solve()
        {
            for(register int i=1;i<=n;++i)
                f[i].resize(m+1,1),g[i].resize(m+1,1);
            dfs1(1,0);
            dfs2(1,0);
            ans=mod-ans;
            for(register int i=1;i<=n;++i)
                ans=(0ll+ans+power(1ll*f[i][m]*g[i][m]%mod,k))%mod;
            write(ans);
        }
    }
    namespace subtask2{
        int a[200005],b[200005];
        inline void dfs1(register int x,register int fa)
        {
            for(register int i=head[x];i;i=e[i].next)
            {
                int v=e[i].to;
                if(v==fa)
                    continue;
                dfs1(v,x);
                a[x]=1ll*a[x]*(a[v]+1)%mod;
            }
        }
        inline void dfs2(register int x,register int fa)
        {
            static int son[200005],pre[200005],suf[200005];
            int cnt=0;
            for(register int i=head[x];i;i=e[i].next)
                if(e[i].to!=fa)
                    son[++cnt]=e[i].to;
            pre[0]=suf[cnt+1]=1;
            for(register int j=1;j<=cnt;++j)
                pre[j]=1ll*pre[j-1]*(a[son[j]]+1)%mod;
            for(register int j=cnt;j>=1;--j)
                suf[j]=1ll*suf[j+1]*(a[son[j]]+1)%mod;
            for(register int j=1;j<=cnt;++j)
                b[son[j]]=(1ll*b[x]*pre[j-1]%mod*suf[j+1]+1)%mod;
            for(register int i=head[x];i;i=e[i].next)
            {
                int v=e[i].to;
                if(v==fa)
                    continue;
                ans=(ans+power(1ll*(b[v]-1)*a[v]%mod,k))%mod;
                dfs2(v,x);
            }
        }
        inline void solve()
        {
            for(register int i=0;i<=n;++i)
                a[i]=b[i]=1;
            dfs1(1,0);
            dfs2(1,0);
            ans=mod-ans;
            for(register int i=1;i<=n;++i)
                ans=(ans+power(1ll*a[i]*b[i]%mod,k))%mod;
            write(ans);
        }
    }
    namespace subtask3{
        inline void solve()
        {
            for(register int i=1;i<=n;++i)
            {
                int l=max(1,i-m),r=min(n,i+m);
                ans=(ans+power(1ll*(i-l+1)*(r-i+1)%mod,k))%mod;
            }
            for(register int i=2;i<=n;++i)
            {
                int l=max(1,i-m),r=min(n,i+m-1);
                ans=(ans+mod-power(1ll*(i-l+1-1)*(r-i+1)%mod,k))%mod;
            }
            write(ans);
        }
    }
    int main()
    {
        n=read(),m=read(),k=read();
        if(n<=200000)
        {
            for(register int i=1;i<n;++i)
            {
                int u=read(),v=read();
                add(u,v),add(v,u);
            }
        }
        if(m==n&&n<=200000)
            subtask2::solve();
        else if(n<=100000)
            subtask1::solve();
        else
            subtask3::solve();
    	return 0;
    }
    

    算法6

    发现(f,g)的转移珂以用长链剖分优化,套上一个可持久化数据结构,需要资瓷区间加、区间乘

    时间复杂度:(O(nlog n))

    期望得分:结合算法5可得84pts

    算法7

    发现是全局加,后缀乘,这样可以像SDOI2019Day1T1 快速查询

    珂以用数组线性维护,为了去掉求逆元的(log),我们珂以用类似于求阶乘逆元的方法(O(n))预处理要用的逆元

    至此,我们得到了一个(O(n))的做法

    期望得分:100pts

    #include <bits/stdc++.h>
    #define mod 998244353
    #define N 1000005
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    inline int power(register int a,register int b)
    {
        int res=1;
        while(b)
        {
            if(b&1)
                res=1ll*res*a%mod;
            a=1ll*a*a%mod;
            b>>=1;
        }
        return res;
    }
    struct edge{
        int to,next;
    }e[N<<1];
    int head[N],cnt=0;
    inline void add(register int u,register int v)
    {
        e[++cnt]=(edge){v,head[u]};
        head[u]=cnt;
    }
    int n,m,k;
    int dp[N],son[N],len[N],val[N],idx[N],tot,inv[N];
    int arr[N<<3],*pos=arr,*f[N<<1],*g[N],ans[2][N],Ans;
    inline void dfs1(register int x,register int fa)
    {
        dp[x]=1;
        for(register int i=head[x];i;i=e[i].next)
        {
            int v=e[i].to;
            if(v==fa)
                continue;
            dfs1(v,x);
            son[x]=len[v]>len[son[x]]?v:son[x];
            dp[x]=1ll*dp[x]*dp[v]%mod;
        }
        if(++dp[x]<mod)
            val[idx[x]=++tot]=dp[x];
        len[x]=len[son[x]]+1;
    }
    inline void init_inv()
    {
        static int pre[N];
        for(register int i=pre[0]=1;i<=tot;++i)
            pre[i]=1ll*pre[i-1]*val[i]%mod;
        int pre_inv=power(pre[tot],mod-2);
        for(register int i=tot;i;--i)
            inv[i]=1ll*pre[i-1]*pre_inv%mod,pre_inv=1ll*pre_inv*val[i]%mod;
    }
    struct node{
        int a,b,inv,pos,num;
    };
    namespace F{
        node tag[N<<1];
        vector<pair<node,vector<pair<int,int> > > >backup[N];
        inline int get(register int u,register int i)
        {
            int res=i<tag[u].pos?f[u][i]:tag[u].num;
            return (1ll*res*tag[u].a+tag[u].b)%mod;
        }
        inline void put(register int u,register int i,register int v)
        {
            f[u][i]=1ll*(v+mod-tag[u].b)*tag[u].inv%mod;
        }
        inline void merge(register int u,register int v,register int l)
        {
            node tmp=tag[u];
            vector<pair<int,int> >vec;
            for(register int i=1;i<=l;++i)
            {
                vec.push_back(make_pair(i,f[u][i]));
                int val=get(v,i-1);
                if(i==tag[u].pos)
                    f[u][tag[u].pos++]=tag[u].num;
                put(u,i,1ll*get(u,i)*val%mod);
            }
            if(l<m)
            {
                int val=get(v,l);
                if(!val)
                    tag[u].pos=l+1,tag[u].num=mod-1ll*tag[u].b*tag[u].inv%mod;
                else
                {
                    int t=inv[idx[v]];
                    vec.push_back(make_pair(0,f[u][0]));
                    for(register int i=0;i<=l;++i)
                        put(u,i,1ll*get(u,i)*t%mod);
                    tag[u].a=1ll*tag[u].a*val%mod;
                    tag[u].b=1ll*tag[u].b*val%mod;
                    tag[u].inv=1ll*tag[u].inv*t%mod;
                }
            }
            if(u<=n)
                backup[u].push_back(make_pair(tmp,vec));
        }
        inline void dfs2(register int x,register int fa)
        {
            if(son[x])
                f[son[x]]=f[x]+1,dfs2(son[x],x),tag[x]=tag[son[x]];
            else
                tag[x]=(node){1,1,1,n,0};
            put(x,0,1);
            for(register int i=head[x];i;i=e[i].next)
            {
                int v=e[i].to;
                if(v==fa||v==son[x])
                    continue;
                f[v]=pos;
                pos+=len[v];
                dfs2(v,x);
                merge(x,v,min(len[v]-1,m));
            }
            ans[0][x]=get(x,min(len[x]-1,m-1));
            ans[1][x]=get(x,min(len[x]-1,m));
            ++tag[x].b;
        }
        inline void rollback(register int u)
        {
            tag[u]=backup[u].back().first;
            for(register int i=0;i<(backup[u].back().second).size();++i)
                f[u][(backup[u].back().second)[i].first]=(backup[u].back().second)[i].second;
            backup[u].pop_back();
        }
    }
    namespace G{
        node tag[N];
        inline int get(register int u,register int i)
        {
            int res=i<tag[u].pos?g[u][i]:tag[u].num;
            return (1ll*res*tag[u].a+tag[u].b)%mod;
        }
        inline void put(register int u,register int i,register int v)
        {
            g[u][i]=1ll*(v+mod-tag[u].b)*tag[u].inv%mod;
        }
        inline void dfs3(register int x,register int fa)
        {
            if(len[x]-m-1>=0)
                put(x,len[x]-m-1,1);
            Ans=(Ans+power(1ll*ans[1][x]*get(x,len[x]-1)%mod,k))%mod;
            if(fa)
                Ans=(Ans-power(1ll*ans[0][x]*(get(x,len[x]-1)+mod-1)%mod,k)+mod)%mod;
            if(!son[x])
                return;
            vector<int> ch;
            int maxlen=0;
            for(register int i=head[x];i;i=e[i].next)
            {
                int v=e[i].to;
                if(v==fa||v==son[x])
                    continue;
                ch.push_back(v);
                maxlen=max(maxlen,len[v]);
            }
            maxlen=min(maxlen,m);
            reverse(ch.begin(),ch.end());
            f[x+n]=pos;
            pos+=maxlen+1;
            F::tag[x+n]=(node){1,1,1,n,0};
            F::put(x+n,0,1);
            for(register int id=0;id<ch.size();++id)
            {
                int v=ch[id];
                F::rollback(x);
                g[v]=pos;
                pos+=len[v];
                for(register int i=max(len[v]-m-1,0);i<len[v];++i)
                {
                    if(m-len[v]+i==-1)
                        g[v][i]=get(x,len[son[x]]-len[v]+i);
                    else
                        g[v][i]=1ll*get(x,len[son[x]]-len[v]+i)*F::get(x,min(len[x]-1,m-len[v]+i))%mod*F::get(x+n,min(maxlen,m-len[v]+i))%mod;
                }
                tag[v]=(node){1,1,1,n,0};
                F::merge(x+n,v,min(len[v]-1,m));
                dfs3(v,x);
            }
            int v=son[x];
            g[v]=g[x];
            tag[v]=tag[x];
            for(register int i=max(len[v]-m,0);i<=len[v]+maxlen-m-1;++i)
            {
                if(tag[v].pos==i)
                    g[v][tag[v].pos++]=tag[v].num;
                put(v,i,1ll*get(v,i)*F::get(x+n,m-len[v]+i)%mod);
            }
            if(maxlen<m)
            {
                int vv=1,tt=1;
                for(register int i=0;i<ch.size();++i)
                    vv=1ll*vv*val[idx[ch[i]]]%mod,tt=1ll*tt*inv[idx[ch[i]]]%mod;
                if(!vv)
                    tag[v].pos=len[v]+maxlen-m,tag[v].num=mod-1ll*tag[v].b*tag[v].inv%mod;
                else
                {
                    for(register int i=max(len[v]-m-1,0);i<=len[v]+maxlen-m-1;++i)
                        put(v,i,1ll*get(v,i)*tt%mod);
                    tag[v].a=1ll*tag[v].a*vv%mod;
                    tag[v].b=1ll*tag[v].b*vv%mod;
                    tag[v].inv=1ll*tag[v].inv*tt%mod;
                }
            }
            ++tag[v].b;
            dfs3(v,x);
        }
    }
    int main()
    {
        n=read(),m=read(),k=read();
        for(register int i=1;i<n;++i)
        {
            int u=read(),v=read();
            add(u,v),add(v,u);
        }
        dfs1(1,0);
        init_inv();
        f[1]=pos;
        pos+=len[1];
        F::dfs2(1,0);
        g[1]=pos;
        pos+=len[1];
        G::tag[1]=(node){1,1,1,n,0};
        G::dfs3(1,0);
        write(Ans);
    	return 0;
    }
    
  • 相关阅读:
    此网页的安全性验证无效并且可能损坏的错误的解决方法
    fixSidebar简介与修正log
    Git可视化极简易教程 —— Git GUI使用方法
    windows平台快速搭建Linux(CentOS)
    CentOS在线安装Mysql5.7
    springboot集成mybatis(二)
    springboot测试、打包、部署
    springboot快速入门
    springboot集成mybatis(一)
    CentOS在线安装JDK
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/11300018.html
Copyright © 2011-2022 走看看