bzoj5250&loj 2473「九省联考 2018」秘密袭击

http://www.elijahqi.win/archives/3356
题目描述

We could have had it all……

我们本该,拥有一切

Counting on a tree……

何至于此,数数树上

Counting on a Tree(CoaT)即是本题的英文名称。

Access Globe 最近正在玩一款战略游戏。在游戏中,他操控的角色是一名 C 国士兵。他的任务就是服从指挥官的指令参加战斗,并在战斗中取胜。C 国即将向 D 国发动一场秘密袭击。作战计划是这样的:选择 D 国的 sss 个城市,派出 C 国战绩最高的 sss 个士兵分别秘密潜入这些城市。每个城市都有一个危险程度 did_id​i​​,C 国指挥官会派遣战绩最高的士兵潜入所选择的城市中危险程度最高的城市,派遣战绩第二高的士兵潜入所选择的城市中危险程度次高的城市,以此类推(即派遣战绩第 iii 高的士兵潜入所选择城市中危险程度第 iii 高的城市)。D 国有 nnn 个城市,n−1 条双向道路连接着这些城市,使得这些城市两两之间都可以互相到达。为了任务执行顺利,C 国选出的 sss 个城市中,任意两个所选的城市,都可以不经过未被选择的城市互相到达。

Access Globe 操控的士兵的战绩是第 kkk 高,他希望能估计出最终自己潜入的城市的危险程度。Access Globe 假设 C 国是以等概率选出任意满足条件的城市集合 SSS,他希望你帮他求出所有可能的城市集合中,Access Globe 操控的士兵潜入城市的危险程度之和。如果选择的城市不足 kkk 个,那么 Access Globe 不会被派出,这种情况下危险程度为 000。

当然,你并不想帮他解决这个问题,你也不打算告诉他这个值除以 998,244,353998, 244, 353998,244,353 的余数,你只打算告诉他这个值除以 64,12364,12364,123 的余数。
输入格式

从标准输入中读入数据。

第 111 行包含 333 个整数 n,k,Wn, k, Wn,k,W,表示 D 国城市的个数、Access Globe 所操控士兵潜入的城市战绩排名以及 D 国的所有城市中最大的危险程度;

第 222 行包含 nnn 个 111 到 WWW 之间的整数 d1,d2,…,dn,表示每个城市的危险程度;

第 333 行到第 n+1n + 1n+1 行,每行两个整数 xi,yix_i , y_ix​i​​,y​i​​,表示 D 国存在一条连接城市 xix_ix​i​​ 和城市 yiy_iy​i​​ 的双向道路。
输出格式

输出到标准输出中。

输出一个整数,表示所有可行的城市集合中,Access Globe 操控的士兵潜入城市的危险程度之和除以 64,12364,12364,123 的余数。
样例
样例输入 1

5 3 3
2 1 1 2 3
1 2
2 3
1 4
1 5

样例输出 1

11

样例解释 1

D 国地图如下,其中危险程度为 ddd 的城市的形状是 (d+3)(d + 3)(d+3) 边形。

Explanation

以下是所有符合条件且选择的城市不少于 333 个的方案:

选择城市 1,2,31, 2, 31,2,3,Access Globe 的士兵潜入的城市危险程度为 111;
选择城市 1,2,3,41, 2, 3, 41,2,3,4,Access Globe 的士兵潜入的城市危险程度为 111;
选择城市 1,2,3,51, 2, 3, 51,2,3,5,Access Globe 的士兵潜入的城市危险程度为 111;
选择城市 1,2,3,4,51, 2, 3, 4, 51,2,3,4,5,Access Globe 的士兵潜入的城市危险程度为 222;
选择城市 1,2,41, 2, 41,2,4,Access Globe 的士兵潜入的城市危险程度为 111;
选择城市 1,2,51, 2, 51,2,5,Access Globe 的士兵潜入的城市危险程度为 111;
选择城市 1,2,4,51, 2, 4, 51,2,4,5,Access Globe 的士兵潜入的城市危险程度为 222;
选择城市 1,4,51, 4, 51,4,5,Access Globe 的士兵潜入的城市危险程度为 222;

而在选择的城市少于 333 时,Access Globe 的士兵潜入的城市危险程度均为 000;

所以你应该输出 (1+1+1+2+1+1+2+2)mod64,123=11。
样例输入 2

10 2 3
2 1 1 3 1 2 3 3 1 3
1 2
2 3
2 4
2 5
2 6
5 7
1 8
8 9
1 10

样例输出 2

435

数据范围与提示
测试点 n=n=n= k≤k\leqk≤ W=W=W= 地图是一条链
111 333 nnn 1,6661,6661,666 保证
222 151515 不保证
333 202020
444 300300300 101010 保证
555 1,6661,6661,666 1,6661,6661,666
666 505050 不保证
777 200200200
888 500500500
999 1,1111,1111,111 10210^210​2​​ 10210^210​2​​
101010 505050 1,1111,1111,111
111111 10210^210​2​​ 1,6661,6661,666
121212 1,6661,6661,666
131313 200200200
141414 500500500
151515 nnn
161616
171717
181818
191919
202020

对于所有的数据,1≤k≤n,1≤di≤W,1≤n,k,W≤1,6661 \leq k \leq n, 1 \leq d_i \leq W, 1\leq n, k, W \leq 1, 6661≤k≤n,1≤d​i​​≤W,1≤n,k,W≤1,666。

考虑怎么去做 直接枚举联通块并不好做 那么不妨枚举每个点对整体答案的贡献 考虑枚举这个点的时候将大于等于我的点设为1 否则设为0 那么就求有多少个联通块以我为根且 其中点数为k即可 那么就考虑首先枚举 我这个根节点是哪个点 然后每次转移的时候该节点首先从父节点转移过来 表示我这个节点必须选 我必选这个点且必选 根节点的方案数 然后做完这个节点就去做子树 做完子树整体更新上来一遍即可

复杂度n^3

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define uint unsigned int
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int mod=64123,N=2000;
struct node{
    int y,next;
}data[N<<1];
int h[N],now,num,v[N],n,m,k;
uint dp[N][N],ans;
inline void inc(uint &x,uint v){x+=v;if (x>=mod) x-=mod;}
inline void dfs(int x,int fa){
    if (v[x]>v[now]||v[x]==v[now]&&now<x) {for (int i=1;i<=k;++i) dp[x][i]=dp[fa][i-1];}
    else for (int i=1;i<=k;++i) dp[x][i]=dp[fa][i];
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (y==fa) continue;dfs(y,x);
    }for (int i=1;i<=k;++i) inc(dp[fa][i],dp[x][i]);
}
inline void gao(int x){
    int tot=1;now=x;
    for (int i=1;i<=n;++i) if (v[i]>v[x]||v[i]==v[x]&&x<i) ++tot;
    if (tot<k) return;memset(dp[x],0,sizeof(dp[x]));dp[x][1]=1;
    for (int i=h[x];i;i=data[i].next) dfs(data[i].y,x);
    inc(ans,v[x]*dp[x][k]%mod);
}
int main(){
    freopen("bzoj5250.in","r",stdin);
    n=read();k=read();m=read();
    for (int i=1;i<=n;++i) v[i]=read();
    for (int i=1;i<n;++i){
        int x=read(),y=read();
        data[++num].y=y;data[num].next=h[x];h[x]=num;
        data[++num].y=x;data[num].next=h[y];h[y]=num;
    }for (int i=1;i<=n;++i) gao(i);printf("%u\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/elijahqi/article/details/80287088