bzoj5250 [九省聯考2018]秘密襲擊coat 樹形dp
題目背景
We could have had it all. . . . . .
我們本該,擁有一切
Counting on a tree. . . . . .
何至於此,數數樹上
Counting on a Tree( CoaT)即是本題的英文名稱。
題目描述
AccessGlobe最近正在玩一款戰略遊戲。在遊戲中,他操控的角色是一名C國士兵。他的任務就是服從指揮官的指令
參加戰鬥,並在戰鬥中取勝。C國即將向D國發動一場秘密襲擊。作戰計劃是這樣的:選擇D國的s個城市,派出C國
戰績最高的s個士兵分別秘密潛入這些城市。每個城市都有一個危險程度di,C國指揮官會派遣戰績最高的士兵潛入
所選擇的城市中危險程度最高的城市,派遣戰績第二高的士兵潛入所選擇的城市中危險程度次高的城市,以此類推
(即派遣戰績第i高的士兵潛入所選擇城市中危險程度第i高的城市)。D國有n個城市,n-1條雙向道路連接著這些
城市,使得這些城市兩兩之間都可以互相到達。為了任務執行順利,C國選出的s個城市中,任意兩個所選的城市,
都可以不經過未被選擇的城市互相到達。AccessGlobe操控的士兵的戰績是第k高,他希望能估計出最終自己潛入的
城市的危險程度。AccessGlobe假設C國是以等概率選出任意滿足條件的城市集合S,他希望你幫他求出所有可能的
城市集合中,AccessGlobe操控的士兵潛入城市的危險程度之和。如果選擇的城市不足k個,那麽AccessGlobe不會
被派出,這種情況下危險程度為0。當然,你並不想幫他解決這個問題,你也不打算告訴他這個值除以998,244,353
的余數,你只打算告訴他這個值除以64,123的余數。
Input
第1行包含3個整數n、k、W
表示D國城市的個數、AccessGlobe所操控士兵潛入的城市戰績排名以及D國的所有城市中最大的危險程度;
第2行包含n個1到W之間的整數d1,d2,...,dn,表示每個城市的危險程度;
第3行到第n+1行,每行兩個整數xi,yi,表示D國存在一條連接城市xi和城市yi的雙向道路
1 ≤ k ≤ n,, 1 ≤ di ≤ W, n, k, W ≤ 1, 666。
Output
輸出一個整數,表示所有可行的城市集合中
AccessGlobe操控的士兵潛入城市的危險程度之和除以64,123的余數。
題解參考https://cnyali-lk.blog.luogu.org/solution-p4365
這題其實正解是拉格朗日插值,結果我太菜了看不懂…啊留個坑把??
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define int long long using namespace std; typedef long long ll; const int maxn=1e5+10; const int mod=64123; int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int k,W,n; int f[2010][5010]; int w[2010],ok[maxn]; int d[maxn]; int head[maxn],cnt; struct edge{int to,nxt;}e[maxn*2]; void add(int x,int y){ e[++cnt]=(edge){y,head[x]}; head[x]=cnt; } void dfs(int x,int fa){ w[x]=ok[x]; for(int i=0;i<=k;i++)f[x][i]=0; f[x][ok[x]]=1; for(int i=head[x];i;i=e[i].nxt){ int u=e[i].to; if(u==fa)continue; dfs(u,x); for(int j=w[x];j>=0;j--){ int tmp=f[x][j];//這個在更新時會改變,所以要特別記錄 for(int q=w[u];q>=0;q--) f[x][min(j+q,k)]=(f[x][min(j+q,k)]+tmp*f[u][q])%mod; } w[x]=min(w[x]+w[u],k); } } #undef int int main() #define int long long { n=read();k=read();W=read(); for(int i=1;i<=n;i++)d[i]=read(); for(int i=1;i<n;i++){ int u=read(),v=read(); add(u,v);add(v,u); } int ans=0; for(int w=1;w<=W;w++){ int cnt=0; for(int i=1;i<=n;i++)cnt+=(ok[i]=d[i]>=w); if(cnt<k)break; dfs(1,0); for(int i=1;i<=n;i++) ans=(ans+f[i][k])%mod; } printf("%lld\n",ans); return 0; }
bzoj5250 [九省聯考2018]秘密襲擊coat 樹形dp