1 条题解

  • 0
    @ 2025-8-24 22:27:10

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 推翻暴政
    ด้้้้้็้้้็็็็็้้้้้็็็็็้้้้้้็็็็็้้้้้็็็็็้้้้้้็็็็็้้้้้็็็็็้้้้้้็็็็็้้้้้็็็็็้้้้推翻@joyskaka 的暴政

    搬运于2025-08-24 22:27:10,当前版本为作者最后更新于2023-10-24 08:39:18,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    一道不算水的黄题。

    首先,对于每个点放置的水果我们可以做出以下的处理:

    因为每个点放置的水果 仅会影响 它的所有祖先节点,所以我们可以考虑记录 ii 节点的祖先数量大小 SizeiSize_i(即它与它的所有祖先),注意要包含它自己。

    现在的问题是,每个点会做出贡献多少次?显然是 2n12^{n-1} 次,我的推导过程如下:

    注意到样例一解释:

    SS 表示选中状态:

    • S=000S=000 贡献 00
    • S=001S=001 贡献 11
    • S=010S=010 贡献 22
    • S=011S=011 贡献 33
    • S=100S=100 贡献 66
    • S=101S=101 贡献 77
    • S=110S=110 贡献 88
    • S=111S=111 贡献 99

    我们考虑同样的想法,[0,2n)[0,2^n) 中,二进制表示下每一位 11 会出现 2n12^{n-1} 次,就可以得到这个结论了。

    故答案公式如下:

    Ans=2n1×i=1nSizeiAns=2^{n-1}\times\large\sum\limits_{i=1}^n Size_i

    线性求出 2n12^{n-1},使用 dfs 求出祖先数量 SizeiSize_i 大小最后统计答案即可,时间复杂度 O(n)O(n)

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    //模数和2的逆元 需要用到2的逆元是因为我的2^(n-1)是用(2^n)/2求得的 非常不聪明
    const long long mod=998244353,inv=499122177;
    const int MAXN=1000005;
    int n,a[MAXN],head[MAXN],tot;
    long long siz[MAXN],base,ans;
    struct edge{
    	int v,nex;
    } e[MAXN<<1];
    //链式前向星建边
    inline void add_edge(int u,int v){
    	e[++tot].v=v;
    	e[tot].nex=head[u];
    	head[u]=tot;
    }
    //深搜求出祖先数量大小
    inline void dfs(int x,int fa){
    	siz[x]=siz[fa]+1;
    	for(int i=head[x];i;i=e[i].nex){
    		int y=e[i].v;
    		if(y==fa)  continue;
    		dfs(y,x);
    	}
    }
    //处理2^(n-1)
    inline void pre(){
    	base=1;
    	for(int i=1;i<=n;i++)  base=(base*2)%mod;
    	base=(base*inv)%mod;
    }
    int main(){
    	scanf("%d",&n);
    	pre();
    	for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
    	for(int i=1;i<n;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add_edge(x,y);
    		add_edge(y,x);
    	}
    	dfs(1,1);
       	//统计答案 注意三个数一起相乘可能会爆long long 所以我们拆成两两相乘
    	for(int i=1;i<=n;i++){
    		siz[i]=(siz[i]*a[i])%mod;
    		ans+=base*siz[i]%mod;
    		ans%=mod;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

    感谢你的阅读,点个赞再走吧~

    • 1

    信息

    ID
    6313
    时间
    1000ms
    内存
    128MiB
    难度
    3
    标签
    (无)
    递交数
    0
    已通过
    0
    上传者