JZOJ 5444. 【NOIP2017提高A组冲刺11.2】救赎
Description
“是的。”我回答,“我不會(huì)忘記你。在森林里我會(huì)一點(diǎn)點(diǎn)記起往日的世界。要記起的大概很多很多:各種人、各種場(chǎng)所、各種光、各種歌曲……”
——村上春樹(shù)《世界盡頭與冷酷仙境》
在沒(méi)有心存在的世界盡頭,音樂(lè)能夠使小鎮(zhèn)居民消散的心重新聚攏成形。作為鎮(zhèn)子里唯一一個(gè)還殘留著些許音樂(lè)記憶的人,我逐漸記起了往昔點(diǎn)滴……
記憶中有一棵無(wú)根樹(shù),有n個(gè)節(jié)點(diǎn)。
對(duì)于一棵有根樹(shù)的每一個(gè)非葉子節(jié)點(diǎn),我們都等概率選中其一個(gè)兒子節(jié)點(diǎn)作為偏好兒子。對(duì)于一條從父親指向兒子的樹(shù)邊(u,v),如果v是u的偏好兒子,則稱(chēng)這條邊為重邊,否則為輕邊。
我們定義一棵有根樹(shù)的權(quán)值為其每一個(gè)節(jié)點(diǎn)到根路徑上的輕邊條數(shù)的和的期望值。
請(qǐng)對(duì)無(wú)根樹(shù)每一個(gè)節(jié)點(diǎn)輸出其為根的有根樹(shù)的權(quán)值。答案模998244353。
Input
文件第一行是一個(gè)正整數(shù)n。
接下來(lái)n-1行,每行兩個(gè)正整數(shù)(x,y)表示一條樹(shù)邊。
Output
輸出文件共n行,每一行一個(gè)整數(shù)表示答案。
Sample Input
5
1 2
1 3
3 4
3 5
Sample Output
3
1
665496238
499122178
499122178
Data Constraint
對(duì)于10%的數(shù)據(jù),保證n<=10。
對(duì)于30%的數(shù)據(jù),保證n<=2000。
對(duì)于100%的數(shù)據(jù),保證n<=10^5。
Solution
利用期望的線性既可以得出對(duì)于一個(gè)有根樹(shù)的答案是,復(fù)雜度 O(N2):
∑i=1n(sizei?1)?(soni?1)soni但是可以發(fā)現(xiàn)換一次根許多點(diǎn)的貢獻(xiàn)都不變,
那么我們先跑出以 1 為根的答案,每次 O(1) 換根后,更改相鄰的邊的貢獻(xiàn)即可。
而且我們可以 O(N) 預(yù)處理出 1?N 的逆元,詳細(xì)方法和證明見(jiàn)下面鏈接:
O(N) 求 1~N 逆元方法及證明
這樣時(shí)間復(fù)雜度就成了大常數(shù)的 O(N) 。
Code
#include<cstdio> using namespace std; typedef long long LL; const int N=1e5+1,mo=998244353; int n,tot; int first[N],next[N<<1],en[N<<1]; int fa[N],size[N],son[N]; LL ans[N],inv[N]; inline int read() {int X=0,w=1; char ch=0;while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();return X*w; } inline void write(int x) {if(x>9) write(x/10);putchar(x%10+'0'); } inline void insert(int x,int y) {next[++tot]=first[x];first[x]=tot;en[tot]=y; } inline void dfs(int x) {size[x]=1,son[x]=0;for(int i=first[x];i;i=next[i])if(en[i]!=fa[x]){fa[en[i]]=x;son[x]++;dfs(en[i]);size[x]+=size[en[i]];} } inline void find(int x) {if(fa[x]) ans[1]=(ans[1]+(son[fa[x]]-1)*inv[son[fa[x]]]%mo*size[x])%mo;for(int i=first[x];i;i=next[i])if(en[i]!=fa[x]) find(en[i]); } inline void work(int x) {int y=fa[x];LL sum=0;if(son[y]) sum=(sum+mo-(n-1)*(son[y]-1)*inv[son[y]]%mo)%mo;if(son[x]) sum=(sum+mo-(size[x]-1)*(son[x]-1)%mo*inv[son[x]]%mo)%mo;fa[y]=x,fa[x]=0;son[x]++,son[y]--;int z=size[x];size[x]=n,size[y]-=z;if(son[x]) sum=(sum+(n-1)*(son[x]-1)%mo*inv[son[x]]%mo)%mo;if(son[y]) sum=(sum+(size[y]-1)*(son[y]-1)%mo*inv[son[y]]%mo)%mo;ans[x]=(ans[y]+sum)%mo;for(int i=first[x];i;i=next[i])if(en[i]!=y) work(en[i]);fa[x]=y,fa[y]=0;son[x]--,son[y]++;size[x]=z,size[y]=n; } int main() {n=read();for(int i=1;i<n;i++){int x=read(),y=read();insert(x,y);insert(y,x);}inv[0]=inv[1]=1;for(int i=2;i<=n;i++) inv[i]=(mo-mo/i)*inv[mo%i]%mo;dfs(1),find(1);for(int i=first[1];i;i=next[i]) work(en[i]);for(int i=1;i<=n;i++) write(ans[i]),putchar('\n');return 0; }總結(jié)
以上是生活随笔為你收集整理的JZOJ 5444. 【NOIP2017提高A组冲刺11.2】救赎的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: O(N) 求 1~N 逆元 模板及证明
- 下一篇: JZOJ 5445. 【NOIP2017