首页 > 其他分享 >2022 ICPC 网络赛(II) H Fast Fourier Transform题解

2022 ICPC 网络赛(II) H Fast Fourier Transform题解

时间:2022-10-10 20:35:40浏览次数:47  
标签:ans1 ._ Fast ICPC 题解 x2 ANS y2 mod

简要题意

给你一棵树,你可以选若干节点为关键点,定义一个选点方案的价值为:所有路径上没有关键点的点对的距离之和。求所有选点方案的价值之和。

题解

一开始和队友都读错题了,以为在一个方案中一条边只会贡献一次,然后这样直接计算每条边的贡献就秒掉了,于是开始疑惑为什么大伙都没有切这个题。

然后邓老师写完代码了发现样例不对,手模样例发现手模也算不对,然后就意识到题读错了,还有五分钟就结束了所以就摆烂了。

题目的关键是要意识到,一对点的贡献只与他们两点之间的距离有关。

显然,只要他们路径上的点不被选,剩下的点随便选都无所谓。

所以若距离为 \(d\) ,它们的贡献可以写成

\[d\times \sum_i (i+2)\times {n-d-1 \choose i}\\ =d\times(n-d+3)\times2^{n-d-2} \]

形如 \(x\cdot y\cdot 2^y\) ,记录当前点的答案为 \(\sum x\cdot y \cdot 2^y\) ,如果想要上传答案给父亲就是 \(x+1,y-1\) ,同时这个维护 \(\sum x\cdot 2^y,\sum y\cdot 2^y,\sum 2^y\) 就能算了。

换根 dp 在第二次 dfs 的时候算当前节点和子树外节点的贡献的时候,就是把父亲节点的所有贡献减去父亲节点与当前子树内节点形成的点对的贡献,再使 \(x+1,y-1\) 即可。

然后是代码

#include <bits/stdc++.h>
#define N 1000006
using namespace std;
typedef long long ll;
int n,o2,yy;
const ll mod=998244353;
vector<int> ed[N];
int fa[N];
struct ANS{
	ll xy2,x2,y2,_2;
	friend ANS operator +(ANS a,ANS b){ 
		a.x2=(a.x2+b.x2)%mod,
		a.xy2=(a.xy2+b.xy2)%mod,
		a.y2=(a.y2+b.y2)%mod,
		a._2=(a._2+b._2)%mod;
		return a;
	}
	friend ANS operator -(ANS a,ANS b){ 
		a.x2=(a.x2-b.x2+mod)%mod,
		a.xy2=(a.xy2-b.xy2+mod)%mod,
		a.y2=(a.y2-b.y2+mod)%mod,
		a._2=(a._2-b._2+mod)%mod;
		return a;
	}
}ans1[N],ans2[N];
ANS add(ANS x){
	ANS a;
	a.xy2=((x.xy2-x.x2+mod+x.y2-x._2+mod)%mod*o2)%mod;
	a.x2=(x.x2+x._2)*o2%mod;
	a.y2=(x.y2-x._2+mod)*o2%mod;
	a._2=x._2*o2%mod;
	a=a+ans1[0];
	return a;
}
ll ksm(ll x,ll y){
	ll res=1;
	while(y){
		if(y&1) res=res*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return res;
}
void dfs1(int x){
	for(int y: ed[x]){
		if(y==fa[x]) continue;
		fa[y]=x,dfs1(y);
		ans1[x]=ans1[x]+add(ans1[y]);
	}
}
void dfs2(int x){
	if(x==1) ans2[x]=ans1[x];
	else ans2[x]=add(ans2[fa[x]]-add(ans1[x]))+ans1[x];
	for(int y: ed[x]){
		if(y==fa[x]) continue;
		dfs2(y);
	}
}
int main(){
	o2=(mod+1)/2;
	scanf("%d",&n);
	yy=n+2;
	ans1[0]._2=ksm(2,yy),ans1[0].y2=yy*ksm(2,yy)%mod;
	ans1[0].xy2=ans1[0].y2,ans1[0].x2=ans1[0]._2;
	int u,v;
	for(int i=1;i<n;i++){
		scanf("%d %d",&u,&v);
		ed[u].push_back(v),ed[v].push_back(u);
	}
	dfs1(1);
	dfs2(1);
	ll ans=0;
	for(int i=1;i<=n;i++) ans=(ans+ans2[i].xy2)%mod;
	o2=ksm(2,6),o2=ksm(o2,mod-2);
	ans=ans*o2%mod;
	cout<<ans;
}

标签:ans1,._,Fast,ICPC,题解,x2,ANS,y2,mod
From: https://www.cnblogs.com/xoslh/p/16736364.html

相关文章

  • SCOI 萌萌哒 题解
    下决心写一道题写一篇题解。题目链接考虑暴力,直接并查集合并相同的数,和今天T1一样。考虑优化这个暴力。因为今天T1题解说要倍增,所以考虑一个长的跟ST表一样的倍增。具......
  • 洛谷 P3488 [POI2009]LYZ-Ice Skates 题解
    错解每次跑二分图匹配,时间复杂度显然爆炸。时间复杂度:我被杀手皇后摸过了正解引入Hall定理:设二分图中\(G=<V_1,V_2,E>,|V_1|\le|V_2|\),则G中存在\(V_1\)到......
  • 【题解】XXI Opencup GP of Tokyo Count Min Ratio
    有\(R\)个红球,\(B\)个蓝球和一个绿球,同色球之间无区别。将其任意排列,令\(l_R,l_B,r_R,r_B\)分别为绿球左/右边的红/蓝球数量。定义一个方案的权值为\(\max\{x\i......
  • Criss Cross OJ【R001】8月月赛I题解合集
    R0011.「T1」积木高塔Solution返回题目简要题意:给定一个矩阵,以及其每一格中完全相同立方体的高度(即个数),求:这座高塔最高点的高度。这座高塔从第\(1\)层到最高......
  • AtCoder Regular Contest 150 (ARC150) - A+B+C+D 题解
    A题意给定一个由0,1和?组成的长为\(n\)序列,其中?需要被替换为0或1,询问是否有且仅有一种?的替换方案使得序列中有\(k\)个1并且这\(k\)个1是连续的序......
  • Fast.Framework(ORM) 应用
    前言 有小伙伴让我出一个应用到框架的博客,我抽空花了点时间,大致的项目搭建起来,为了大家更好的理解采用经典的三层架构。了解CQRS架构的小伙伴也可以自己尝试一下。演示......
  • [题解]守护者的挑战
    题目描述打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜寻着关押applepi的监狱的所在地。突然,眼前一道亮光闪过。“我,Nizem,是黑魔法圣殿的守卫者。如果你能通......
  • Luogu P6880 [JOI 2020 Final] オリンピックバス 题解
    [P6880JOI2020Final]オリンピックバス-洛谷|计算机科学教育新生态(luogu.com.cn)两条前置知识:在图\(G\)上构造根为\(x\)的最短路树\(T\),我们删除任意一条......
  • ARC150 A+C题题解。
    如题,ARC150A题C题的解题报告。#A-Continuous1###题意:有1,0,?组成的一个序列(?可以为0/1),问恰好有且仅有k个i,且连续的情况有多少种。###分析:考虑O(n).常见为转......
  • FastAdmin 开源常用命令笔记
    FastAdmin开源常用命令笔记常规命令TODO特殊的命令1.less编译将fastadmin.less编译为fastadmin.csslessc./public/assets/less/fastadmin.less./public/asse......