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;
}

原文地址:https://www.cnblogs.com/Nan-Cheng/p/9735259.html

时间: 2024-10-08 14:55:51

bzoj5250 [九省联考2018]秘密袭击coat 树形dp的相关文章

[九省联考2018]秘密袭击coat

树形dp碾压标算 这道题目我写了60分的暴力(N^2*k),没有优化,只是说一说树形dp相关. 这道题我们可以转化一下,我们可以考虑每一个点对答案的贡献.这道题可以转化为以该点为根的树中包含根的连通块,且其中有k个点大于等于根的危险度的方案数.这里"等于"有一定的问题,就是同一种连通块可能会被其他的根重复统计,所以要特判一下,dan[s]==pan&&s<root 才认为其合法. 状态转移是O(k)的,具体看代码: code: #include<iostre

解题:九省联考2018 秘密袭击CoaT

题面 按照*Miracle*的话来说,网上又多了一篇n^3暴力的题解 可能是因为很多猫上树问题虽然很好,但是正解性价比比较低? 我当时在考场上划水的时候手玩了5pts 直接做不可做,转化为统计贡献:$O(n)$枚举每个权值,直接统计第k大大于等于这个权值的联通块个数的和- -这样每个权值x恰会贡献x次. 将所有大于等于当前权值的点点权赋为1,其余点点权赋为零,然后就是$O(n^2)$树形背包:设$dp[i][j]$表示以i为根的子树里选出(新)点权和为j的联通块,且联通块必须包含i自身的方案数.

luogu P4365 [九省联考2018]秘密袭击coat

luogu 这里不妨考虑每个点的贡献,即求出每个点在多少个联通块中为第\(k\)大的(这里权值相同的可以按任意顺序排大小),然后答案为所有点权值\(*\)上面求的东西之和 把比这个点大的点看成\(1\),小于等于他的看成\(0\),那么就是要求出包含枚举的那个点并且权值和为\(k-1\)的联通块个数,可以树型\(dp\),设\(f_{x,j}\)表示联通块最上面的点为\(x\)并且权值和为\(j\)的联通块数,转移树型背包即可,具体细节见代码.复杂度可以做到\(O(nk)\) 所以总复杂度为\(

[九省联考2018]秘密袭击coat 伪&#183;题解

爆算碾标程实例 不太会多项式……不太会线段树合并 那就只能O(n^2*w^2)爆算+乱搞优化(见代码) (这里网上都说是O(n*w^2),我不太明白,也许是我算的不对,望有识之士教我) 愣是卡进luogu最优解第3页 自以为要卡常数,结果卡了好久以后发现是死循环…… #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; co

【BZOJ5248】【九省联考2018】一双木棋(搜索,哈希)

[BZOJ5248][九省联考2018]一双木棋(搜索,哈希) 题面 BZOJ Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且 这个格子的左侧及上方的所有格子内都有棋子. 棋盘的每个格子上,都写有两个非负整数,从上到下第i行中从左到右第j列的格子上的两个整数记作Aij.Bij.在 游戏结束后,菲菲和牛牛会分别计算自己

[luogu] P4364 [九省联考2018]IIIDX(贪心)

P4364 [九省联考2018]IIIDX 题目背景 Osu 听过没?那是Konano 最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏.现在,他在世界知名游戏公司KONMAI 内工作,离他的梦想也越来越近了. 这款音乐游戏内一般都包含了许多歌曲,歌曲越多,玩家越不易玩腻.同时,为了使玩家在游戏上氪更多的金钱花更多的时间,游戏一开始一般都不会将所有曲目公开,有些曲目你需要通关某首特定歌曲才会解锁,而且越晚解锁的曲目难度越高. 题目描述 这一天,Konano 接到了一个任务

九省联考 2018 游记

Day0:乘火车到了上海.明天就是激动人心的比赛啦 深夜和室友看<我在七年后等你>.这真是一款不错的手游,让人印象深刻啊 Day1:迷迷糊糊到了学校.编程环境是Win7?不太习惯啊. T1:一眼状压dp题. T2:肯定可以建成一棵树,然后直接贪心?不对啊,T2不应该这么水啊(开始怀疑) T3:乍一看怎么一点思路没有啊. 8:40~11:10:持续思考T3中. 11:10:终于有思路了!如果直接NTT向上dp的话,因为链的情况复杂度会不对,所以似乎可以树剖!用线段树分治和NTT处理重链上的dp!

[BZOJ5251][九省联考2018]劈配(网络流)

5251: [2018多省省队联测]劈配 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 33  Solved: 22[Submit][Status][Discuss] Description 一年一度的综艺节目<中国新代码>又开始了. Zayid从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了. 题目描述 轻车熟路的Zayid顺利地通过了海选,接下来的环节是导师盲选,这一阶段的规则是这样的: 总共n名参赛选手(编号

[BZOJ5248][九省联考2018]双木棋chess

bzoj luogu sol 首先,要保证一个格子的左边和上方都放满了棋子,就需要这个点的左上方那个矩形都放满了棋子. 这样放旗子状态就会是一个自左下至右上的轮廓线. 状态数? 跟\(yyb,ppl\)讨论了一下状态数理论上应该是\(C_{20}^{10}\)啊. 然而... #include<cstdio> #include<algorithm> using namespace std; int n,m,a[20],tot; void dfs(int u) { if (u==n+