首页 > 其他分享 >[SNOI2024]公交线路 题解

[SNOI2024]公交线路 题解

时间:2024-01-24 13:56:54浏览次数:38  
标签:sz cnt int 题解 叶子 IL 公交线路 SNOI2024 reg

为啥洛谷现有的题解全是 \(O(n^2\log n)\) 的做法?给个好写的 \(O(n^2)\) 做法。

感觉这题是这套题中除了 D1T1 以外最简单的题(


显然最远的距离一定由两个叶子贡献,我们拎出一个非叶节点为根,分析一些性质。

考虑两个叶子 \(u,v\) 何时距离 \(\le 2\),这要求它们所一步能到达的最浅点 \(f(u),f(v)\) 为祖先后代关系。不妨设 \(f(u)\) 为 \(f(v)\) 的祖先,还要求 \(u\) 存在一个走一步的方式走入 \(f(v)\) 的子树中。容易发现这便是充要条件。

考虑枚举 \(x\) 表示最深的 \(f(u)\),这个限制肯定最严。现在要求所有叶子都可以一步走到 \(x\),并且存在一个在其子树内的叶子满足所能达到的最浅点为 \(x\)。

注意到第二个限制处理起来并不是很方便,可以先去掉这个条件,再扣掉所有在 \(x\) 子树内的叶子都能达到 \(x\) 的父亲的方案数。本质就是点数减边数等于一这个经典容斥。

只有第一个限制后直接做还是不好做,考虑容斥,这样就变成有一些边不能选,这是方便 dp 的。如果对所有叶子容斥跑背包的话是 \(O(n^3)\) 的,考虑优化。

注意到只对子树内的叶子跑这个算法就是树形背包,复杂度为 \(O(n^2)\),这是可以接受的。

于是我们只容斥子树内的叶子,由于只剩下最后一类反子树的点没有考虑,在确定了前面的信息之后我们是可以直接计算符合题意的方案数的,这样就把复杂度优化到了 \(O(n^2)\)。

最后剩下的一点问题就是扣掉都能达到 \(x\) 的父亲的方案数,依旧考虑类似的做法,\(O(n^2)\) 计算是容易的。

#include<bits/stdc++.h>
#define IL inline
#define reg register
#define mod 998244353
#define N 3030
IL int read()
{
    reg int x=0; reg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}

IL int Add(reg int x,reg int y){return x+y<mod?x+y:x+y-mod;}
IL int Sub(reg int x,reg int y){return x<y?x-y+mod:x-y;}
IL void Pls(reg int &x,reg int y){x=Add(x,y);}
IL void Dec(reg int &x,reg int y){x=Sub(x,y);}
IL int Mul(reg int x,reg int y){reg long long r=1ll*x*y; return r<mod?r:r%mod;}

int pw[N*N],c[N][N],con[N][N];

IL void init(reg int n)
{
    pw[0]=1;
    for(reg int i=1;i<=n*n;++i)pw[i]=Mul(pw[i-1],2);
    for(reg int i=0,j;i<=n;++i)
    {
        con[i][0]=1;
        for(j=1;j<=n;++j)con[i][j]=Mul(con[i][j-1],Sub(pw[i],1));
    }
    for(reg int i=0;i<=n;++i)c[i][0]=1;
    for(reg int i=1,j;i<=n;++i)for(j=1;j<=i;++j)c[i][j]=Add(c[i-1][j],c[i-1][j-1]);
}

int n,rt,ans;
std::vector<int>G[N];

IL void add(reg int u,reg int v){G[u].push_back(v),G[v].push_back(u);}

int fa[N],sz[N],cnt[N];

void dfs(reg int u)
{
    sz[u]=1,cnt[u]=G[u].size()==1;
    for(reg auto v:G[u])if(!sz[v])
        fa[v]=u,dfs(v),sz[u]+=sz[v],cnt[u]+=cnt[v];
}

IL int A(reg int n){return n*(n-1)>>1;}

main()
{
    n=read();
    if(n<=2)puts("1"),exit(0);
    init(n);
    for(reg int i=n;--i;)add(read(),read());
    for(rt=1;G[rt].size()==1;++rt);
    dfs(rt);
    for(reg int u=1,i,j,w,up;u<=n;++u)
    {
        static int f[N],g[N];
        for(i=1;i<=n;++i)f[i]=0;
        f[1]=up=1;
        for(reg auto v:G[u])if(v!=fa[u])
        {
            for(i=1;i<=up;++i)for(j=0;j<=cnt[v];++j)
            {
                w=Mul(Mul(f[i],c[cnt[v]][j]),pw[i*(sz[v]-j)]);
                if(j&1)Dec(g[i+sz[v]-j],w); else Pls(g[i+sz[v]-j],w);
            }
            up+=sz[v];
            for(i=1;i<=up;++i)f[i]=g[i],g[i]=0;
        }
        reg int a0=cnt[u],b0=sz[u]-a0,a1=cnt[rt]-cnt[u],b1=n-sz[u]-a1;
        w=0;
        for(i=1;i<=up;++i)Pls(w,Mul(Mul(f[i],pw[i*b1]),con[i][a1]));
        for(reg auto v:G[u])if(v!=fa[u])w=Mul(w,pw[A(sz[v])]);
        w=Mul(w,pw[A(n-sz[u])]),Pls(ans,w),w=0;
        for(i=0;i<=a0;++i)
        {
            reg int k=Mul(Mul(c[a0][i],pw[(a0-i)*b1]),con[b0+a0-i][a1]);
            if(i&1)Dec(w,k); else Pls(w,k);
        }
        w=Mul(w,pw[A(a0+b0)+A(a1+b1)+b0*b1]),Dec(ans,w);
    }
    printf("%d\n",ans);
}

标签:sz,cnt,int,题解,叶子,IL,公交线路,SNOI2024,reg
From: https://www.cnblogs.com/Nesraychan/p/17984453

相关文章

  • 【题解 P4197】 Peaks
    Peaks题目描述在Bytemountains有\(n\)座山峰,每座山峰有他的高度\(h_i\)。有些山峰之间有双向道路相连,共\(m\)条路径,每条路径有一个困难值,这个值越大表示越难走。现在有\(q\)组询问,每组询问询问从点\(v\)开始只经过困难值小于等于\(x\)的路径所能到达的山峰中第\(......
  • 【题解 P3293】 美味
    [SCOI2016]美味题目描述一家餐厅有\(n\)道菜,编号\(1,2,\ldots,n\),大家对第\(i\)道菜的评价值为\(a_i\)。有\(m\)位顾客,第\(i\)位顾客的期望值为\(b_i\),而他的偏好值为\(x_i\)。因此,第\(i\)位顾客认为第\(j\)道菜的美味度为\(b_i\oplus(a_j+x_i)\),\(\opl......
  • 2024寒假集训 进阶训练赛 (六)部分题解
    A统计单词数题解注意是否是单词。CODECPP#include<iostream>#include<string>#include<algorithm>usingnamespacestd;intmain(){stringword,article;getline(cin,word);getline(cin,article);//转换为小写字母transform(word.beg......
  • Romberg 数值积分算法+P3779 题解(马上写完)
    Romberg算法吊打Simpson的且不玄学(没有什么十五倍)的数值积分算法。缺点是过程复杂一点,但是只体现在证明上,代码很短。铺垫算法梯形求积公式公式\[\int_a^bf(x)dx\approx\frac{(f(a)+f(b))(b-a)}2\\\text{令}(1)=\frac{(f(a)+f(b))(b-a)}2\]计算梯形求积公式的误差......
  • 前端打包后上传至服务器,发现css样式都未生效,查看请求preview预览格式不正确问题解决
    参考:https://blog.csdn.net/wzj_110/article/details/112850811 我的问题前端打包后上传至服务器,发现css样式都未生效,查看css请求,发现preview预览格式不正确,Response-Headers里的Content-type未对应 原因服务器的nginx配置中, mime.types文件缺失。 原理 MIME:Multip......
  • P2627 [USACO11OPEN] Mowing the Lawn G ( [USACO Open11] 修剪草坪/P2034 选择数字 )题
    P2627[USACO11OPEN]MowingtheLawnG搬运工单调队列优化DP简单题,和P2034重了题意:给定一行\(n\)个非负整数\(a_1\cdotsa_n\)。现在你可以选择其中若干个数,但不能有超过\(k\)个连续的数字被选择。你的任务是使得选出的数字的和最大。(直接抄的2034)正着考虑发现很麻烦,......
  • LOJ3990/LG9602 IOI2023 足球场 题解 (区间DP+精简无用状态)
    首先考虑一个足球场长啥样才是合法的。发现一个点能只拐弯一次到达另一个点,可以分为两种情况:先左右走,再上下走或先上下走,后左右走。无论哪种情况,都要求我们走一步使得和目标点一个轴相同,再走一步使得另一个轴也相同,所以加入把每一行选择的格子看成一个区间(因为如果不连续显然是......
  • CF327C Magic Five 题解
    CF327CMagicFive搬运工单调队列优化DP加等比数列求和首先\(5\)的倍数要求末尾是\(0\)或\(5\)所以我们只用看给定字符串的\(0\)和\(5\)就好,我们钦定他是最终的数的末尾。在他之前的选择删掉,在他之后的全部删掉,方案数就是\(2^{pow-1}\),答案累加就可以了。容易想到......
  • P2254 [NOI2005] 瑰丽华尔兹 题解
    P2254[NOI2005]瑰丽华尔兹搬运工单调队列优化DP还是先朴素,设\(f_{t\i\j\d}\)表示在第\(t\)个时刻,在\(i,j\)位置上,上一步是停留还是滑动的最大步数。这个就是四个方向随便转移。\(T_{max}=4*10^4\)这么做肯定不行。发现\(k\)很小,只有\(200\),所以不妨让\(k\)......
  • P2569 [SCOI2010] 股票交易 题解
    P2569[SCOI2010]股票交易搬运工稍微复杂一点的单调队列优化DP直接设\(f_{i\j}\)表示在第\(i\)天,手上还剩\(j\)个股票时的最大收入。容易写出状态转移方程:\(f_{i\j}=max\{f_{k\t}+(t-j)\cdotw\}\),这样不好看,我们可以拆成这样的形式:\[f_{i\j}=max\{f_{k\t}+t\cdo......