[九省联考2018] 秘密袭击coat
题目背景
We could have had it all. . . . . .
我们本该,拥有一切
Counting on a tree. . . . . .
何至于此,数数树上
Counting on a Tree(CoaT)即是本题的英文名称。
题目描述
Access Globe 最近正在玩一款战略游戏。在游戏中,他操控的角色是一名C 国士 兵。他的任务就是服从指挥官的指令参加战斗,并在战斗中取胜。
C 国即将向D 国发动一场秘密袭击。作战计划是这样的:选择D 国的s 个城市, 派出C 国战绩最高的s 个士兵分别秘密潜入这些城市。每个城市都有一个危险程度d_idi ,
C 国指挥官会派遣战绩最高的士兵潜入所选择的城市中危险程度最高的城市,派遣战绩第二高的士兵潜入所选择的城市中危险程度次高的城市,以此类推(即派遣战绩第i高的士兵潜入所选择城市中危险程度第i 高的城市)。D 国有n 个城市,n - 1 条双向道路连接着这些城市,使得这些城市两两之间都可以互相到达。为了任务执行顺利,C 国选出的s 个城市中,任意两个所选的城市,都可以不经过未被选择的城市互相到达。
Access Globe 操控的士兵的战绩是第k 高,他希望能估计出最终自己潜入的城市的 危险程度。Access Globe 假设C 国是以等概率选出任意满足条件的城市集合S ,他希望你帮他求出所有可能的城市集合中,Access Globe 操控的士兵潜入城市的危险程度之和。如果选择的城市不足k 个,那么Access Globe 不会被派出,这种情况下危险程度为0。
当然,你并不想帮他解决这个问题,你也不打算告诉他这个值除以998 244 353 的 余数,你只打算告诉他这个值除以64,123 的余数。
输入输出格式
输入格式:
从文件coat.in 中读入数据。
第1 行包含3 个整数n、k、W,表示D 国城市的个数、Access Globe 所操控士兵 潜入的城市战绩排名以及D 国的所有城市中最大的危险程度;
第2 行包含n 个1 到W 之间的整数d_1d1 ; d_2d2 ; ... d_ndn ,表示每个城市的危险程度;
第3 行到第n + 1 行,每行两个整数x_ixi ; y_iyi ,表示D 国存在一条连接城市x_ixi 和城市y_iyi 的双向道路。
输出格式:
输出到文件coat.out 中。 输出一个整数,表示所有可行的城市集合中,Access Globe 操控的士兵潜入城市的危险程度之和除以64,123 的余数。
输入输出样例
说明
D 国地图如下,其中危险程度为d 的城市的形状是(d + 3) 边形。
以下是所有符合条件且选择的城市不少于3 个的方案:
• 选择城市1、2、3,Access Globe 的士兵潜入的城市危险程度为1;
• 选择城市1、2、3、4,Access Globe 的士兵潜入的城市危险程度为1;
• 选择城市1、2、3、5,Access Globe 的士兵潜入的城市危险程度为1;
• 选择城市1、2、3、4、5,Access Globe 的士兵潜入的城市危险程度为2;
• 选择城市1、2、4,Access Globe 的士兵潜入的城市危险程度为1;
• 选择城市1、2、5,Access Globe 的士兵潜入的城市危险程度为1;
• 选择城市1、2、4、5,Access Globe 的士兵潜入的城市危险程度为2;
• 选择城市1、4、5,Access Globe 的士兵潜入的城市危险程度为2;而在选择的 城市少于3 时,Access Globe 的士兵潜入的城市危险程度均为0;
所以你应该输出(1 + 1 + 1 + 2 + 1 + 1 + 2 + 2) mod 64 123 = 11。
题解见注释,,,O(N^3)卡过23333.
/* 所有联通块第k大的和 => for V = 1 to W ans+=(所有第K大>=V的联通块个数) 外层枚举一个V f[i][j] 表示 以i为根的子树中 选了 j个 权值>=V 的点的方案数(必须和i联通) */ #include<bits/stdc++.h> #define ll long long const int ha=64123; const int maxn=1700; using namespace std; #define pb push_back vector<int> g[maxn]; int n,K,W,V,f[maxn][maxn]; int w[maxn],ans=0,siz[maxn]; int hz[maxn]; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x; } void dfs(int x,int fa){ siz[x]=w[x]>=V; f[x][siz[x]]=1; int to; for(int i=g[x].size()-1;i>=0;i--){ to=g[x][i]; if(to==fa) continue; dfs(to,x); for(int l=siz[x];l>=0;l--) if(f[x][l]) for(int j=siz[to];j>=0;j--) if(f[to][j]) f[x][l+j]=add(f[x][l+j],f[x][l]*(ll)f[to][j]%ha); siz[x]+=siz[to]; } for(int i=K;i<=siz[x];i++) ans=add(ans,f[x][i]); } int main(){ scanf("%d%d%d",&n,&K,&W); for(int i=1;i<=n;i++) scanf("%d",w+i),hz[w[i]]++; int uu,vv; for(int i=1;i<n;i++){ scanf("%d%d",&uu,&vv); g[uu].pb(vv),g[vv].pb(uu); } for(int i=W;i;i--) hz[i]+=hz[i+1]; for(V=1;V<=W;V++) if(hz[V]>=K){ memset(f,0,sizeof(f)); dfs(1,1); } printf("%d\n",ans); return 0; }