1. 程式人生 > >bzoj5250 [九省聯考2018]秘密襲擊coat 樹形dp

bzoj5250 [九省聯考2018]秘密襲擊coat 樹形dp

ali ios globe zoj head pre efi algo return

題目背景

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