NOI2018模擬3 11 派對

2021-08-16 20:17:55 字數 2800 閱讀 2762

time limits: 2000 ms memory limits: 262144 kb

description

你想舉行一場派對,有m個朋友會來參加。

你有n個房間,由n-1條道路連線,形成乙個樹結構。你需要給每個朋友安排乙個房間,滿足以下條件:

每個朋友住在乙個單獨的房間;

存在乙個房間(不一定要有人),使得每個朋友到它的距離不超過k。求方案數對998244353取模的結果。

input

第一行三個整數n,m,k,接下來n-1行每行三個整數ui,vi,wi,表示存在一條連線ui和vi,長度為wi的道路。

output

輸出一行乙個整數表示答案。

sample input

5 2 7

1 2 4

3 2 8

2 4 2

4 5 6

sample output

data constraint

subtask 1 (8pts):n<=20。

subtask 2 (31pts):n<=5000。

subtask 3 (21pts):m=2且wi=1。

subtask 4 (40pts):無特殊限制。

對於全部資料,1<=m<=n<=10^5,1<=k,wi<=10^9。

考慮把這一顆樹變成一顆以1位根的樹

那麼對於每一種合法的方案,一定有乙個最高的點(也就是深度最淺的點)使得它可以成為這一種方案中的和每乙個小朋友的距離都不超過k的點,並且對於任意深度更淺的點都有乙個選取的點與其距離》k,我們考慮在這個最高的點統計這一種方案

那麼對於乙個點x,我們可以選取的點就是與它<=k的點,並且我們至少要選取乙個和fa[x]的距離》k的點,使得這種方案對應的最高點是x

設f[i]表示與點i距離<=k的點的個數,這個東西可以用點剖來求

注意到與x距離<=k,與fa[x]距離》k的點一定在x的子樹中,那麼我們直接使用線段樹合併來找到這樣的所有點,然後問題就變成了現在有f[x]個點,要從中選取m個點,並且有z個點是必須至少選乙個的

正難則反,直接全部方案減去全部不選就好了

#include

#include

#include

#include

#include

#define fo(i,a,b) for(i=a;i<=b;i++)

#define ll long long

using

namespace

std;

const

int maxn=1e5+5,md=998244353;

struct pw[maxn];

int tree[maxn*120][3],root[maxn],size[maxn],f[maxn];

ll zo[maxn],c[maxn],mx,ni[maxn],wc[maxn],dis[maxn],ans;

int fi[maxn],ne[maxn*2],dui[maxn*2],dui1[maxn*2],qc[maxn];

int i,j,k,l,m,n,x,y,now,p,z,zz,rc,rot;

bool bz[maxn];

int cmp(p x,p y)

ll c(int x,int y)

ll quickmi(ll x,int y)

return t1;

}void ge_size(int x,int y)

}void ge_root(int x,int y)

s=max(s,rc-size[x]+1);

if (svoid ge_dis(int x,int y)

}void calc(int x,int y,int z)

}void dfs(int x)

}void change(int v,ll l,ll r,ll x) else

}void find(int v,ll l,ll r,ll x,ll y)

}}void mira_adin(int rt,int x,int y,ll go)

}void dfs(int x,int y)

dfs(dui[i],x);

size[x]=size[x]+size[dui[i]];

if (size[dui[i]]>size[big])

}if (big==0) change(root[x],1,mx,zo[x]); else

}z=0;

find(root[x],1,mx,zo[x],zo[x]+k); zz=z;

z=0;

if (y) find(root[x],1,mx,zo[x]-la,zo[x]-la+k);

z=zz-z;

if (f[x]>=m && z>0) ans=(ans+c(m,f[x]))%md;

if (f[x]-z>=m && z>0) ans=(ans-c(m,f[x]-z)+md)%md;

}int main()

wc[0]=1;

fo(i,1,n) wc[i]=(wc[i-1]*i)%md;

fo(i,0,n)

ni[i]=quickmi(wc[i],md-2);

fo(i,m,n) c[i]=c(m,i);

fo(i,1,n-1)

dfs(1);

memset(size,0,sizeof(size));

p=n;

dfs(1,0);

ans=(ans*wc[m])%md;

printf("%d\n",ans);

return

0;}

NOI2018 氣泡排序

noi2018 氣泡排序 題解性質 模型轉化 首先,乙個排列是 好 的,當且僅當 每個數,要麼是字首最大值,要麼是字尾最小值。討論i和pi的關係即可證明 也就是,排列不能存在 3的下降子串行!換句話說,假設之前填了i個數,最大值是mx,那麼第i 1個數,要麼是剩下數的最小值,要麼是比mx大的數。字典...

NOI2018 氣泡排序

題面 吐槽 好像發的pdf題面的冒泡是掛掛的,還好我還會氣泡排序 逃 具體思路 首先發現當這個序列的最長下降序列長度大於2時,一定不符合要求 那麼我們可以想出乙個 o n 2 的dp f i,j 表示前 i 個數,設其中最大的數為 mx 後面的數中有 j 個數比 mx 小的方案數 然後發現 f i,...

NOI2018 歸程 題解

容易發現,當水位線確定了,圖會被分成若干個連通塊,連通塊裡的點可以互相到達,故連通塊內點的答案為其中的點到 1 的距離的最小值,這個可以先 dijkstra 預處理求出 spfa 死了 那考慮怎麼維護連通塊。可持久化並查集?感覺不好搞,有一種神奇的演算法 kruscal 重構樹。其實就是 krusc...