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...