5250: [2018多省省队联测]秘密袭击
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 3 Solved: 0
[Submit][Status][Discuss]Description
【题目背景】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的余数。Sample Input
5 3 3
2 1 1 2 3
1 2
2 3
1 4
1 5Sample Output
11HINT
请不要提交,原题空间限制为1G,单点时限5s.请下载数据自行测评.数据如下:https://begin.lydsy.com/JudgeOnline/upload/5240.rar
Source
[Submit][Status][Discuss]
正解好像是从本质理解FFT?听起来就不可做。
考虑暴力踩标程。我们枚举每个点,算出以这个点为第k名的连通块个数。
我们将枚举的点作为根DP,因为可能有重复,所以规定相等的点只能从编号小的走向大的,这题就成了某道CF原题了。
下面代码的主要思想是,递归时由父亲将信息传下来,然后修改当前点的信息,然后递归到子节点完善信息,再将信息返回给父亲。这个思路感觉比较新奇。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=l; i<=r; i++) 5 using namespace std; 6 7 const int N=4010,mod=64123; 8 int n,k,W,cnt,S,ans,u,v,to[N<<1],nxt[N<<1],h[N],d[N],f[N][N]; 9 10 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 11 void up(int &x,int y){ x+=y; if (x>=mod) x-=mod; } 12 13 void dfs(int x,int fa,int g[]){ 14 if (d[x]>d[S] || (d[x]==d[S] && x>S)) rep(i,1,k) f[x][i]=g[i-1]; 15 else rep(i,1,k) f[x][i]=g[i]; 16 for (int i=h[x]; i; i=nxt[i]) if (to[i]!=fa) dfs(to[i],x,f[x]); 17 rep(i,1,k) up(g[i],f[x][i]); 18 } 19 20 void calc(int x){ 21 int tot=1; 22 rep(i,1,n) if (d[i]>d[x] || (d[i]==d[x] && i>x)) tot++; 23 if (tot<k) return; 24 S=x; memset(f[x],0,sizeof(f[x])); f[x][1]=1; 25 for (int i=h[x]; i; i=nxt[i]) dfs(to[i],x,f[x]); 26 ans=(ans+1ll*d[x]*f[x][k])%mod; 27 } 28 29 int main(){ 30 freopen("coat.in","r",stdin); 31 freopen("coat.out","w",stdout); 32 scanf("%d%d%d",&n,&k,&W); 33 rep(i,1,n) scanf("%d",&d[i]); 34 rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u); 35 rep(i,1,n) calc(i); 36 printf("%d ",ans); 37 return 0; 38 }