题目链接

考虑枚举好点的集合。此时要考虑的问题是如何填入\(1\sim n\)这些数使得恰好我们枚举到的这些点是好点,即:求出有多少种合法的填数方案。

\(1\)号点一定是好点。那么除\(1\)号点外每个点的祖先中必有至少一个好点。定义\(u\)的祖先中离\(u\)最近的好点,为\(u\)的祖先好点\((2\leq u\leq n)\)。

对除\(1\)外的每个点:

  • 如果它是好点,我们就从它的祖先好点向它连一条边。(称为“第一类边”)

  • 如果它是不是好点,就从它向它的祖先好点连一条边。(称为“第二类边”)

那么对于任意一条边\(a\rightarrow b\),它代表的含义是一种限制:\(val_a<val_b\)。显然,一种填数方案合法,当且仅当满足所有这些限制。

这些边的方向有上有下,让我们非常头疼。如果只有一些第一类限制,问题相当于给定一棵树,求有多少种填数方案使得祖先的权值总是小于后代。这是非常简单的经典问题(其答案是\(n!\prod_u\frac{1}{sz_u}\))。

所以我们可以考虑对第二类边做容斥。即:我们强行把一些坏点向其祖先好点连的边的方向反过来,求出此时的填数方案数,再乘以\((-1)^{\text{被反向的坏点个数}}\),加入答案。当然,我们不能暴力枚举使哪些坏点反向,否则总复杂度变为\(O(3^n\times n)\),且没什么优化前途。

考虑DP。设\(dp[u][i]\)表示考虑了\(u\)的子树,共选出\(i\)个有限制的点(既包括所有原本就是好点的点,也包括一些被容斥强行反向的坏点)的填数方案数。注意:
这里的填数方案只考虑了这\(i\)个有限制的点,对于无限制的坏点我们统计答案时再计算。并且对于这\(i\)个有限制的点,我们只考虑它们填的数的相对大小关系,这样方便转移。

把\(u\)的子树的方案合并起来,就是做一个简单的树上背包。也就是大家所熟知的那个看起来是\(O(n^3)\)实际上是\(O(n^2)\)的算法。这里不再赘述。

设我们把\(u\)的所有儿子的DP值合并得到\(g\),即:在\(u\)的所有儿子子树内,选出\(i\)个有限制的点的方案数为\(g[i]\)。

然后转移,考虑\(u\)。

  • 若\(u\)是好点。则\(u\)上填的数必是\(i\)个点中最小的,因为我们这里只考虑相对大小关系,因此\(u\)上一定填\(1\)。故\(dp[u][i]=g[i-1]\)。

  • 若\(u\)不是好点。

    • 若\(u\)被选为有限制的点(即\(u\)向其祖先好点连的边被在容斥中反向了):则\(u\)上可以填任意数(因为\(u\)有祖先好点,这个祖先好点在转移时只能填\(1\),所以它的值必然比\(u\)小),所以\(u\)有\(i\)种填法。再乘上容斥系数。所以我们得到:\(dp[u][i]=(-1)\times i\times g[i-1]\)。

    • 若\(u\)没有被选为有限制的点,则\(dp[u][i]=g[i]\)。

    综上所述:\(dp[u][i]=(-1)\times i\times g[i-1]+g[i]\)。

考虑统计在当前好点集合下的方案数。

设好点集合大小为\(c\)。枚举选出了\(i\)个有限制的点。则方案数为:

\[
x=\sum_{i=c}^{n}dp[1][i]\times{n\choose i}\times(n-i)!
\]

我们把这个方案数贡献到答案里,即\(ans+=x\times k^c\)。

至此,我们实现了\(O(2^n\times n^2)\)的复杂度并喜提\(0\)分。但其实我们离正解只有一步之遥。

我们完全可以不枚举好点集合,在DP转移时讨论\(u\)是不是好点即可。至于\(k^c\)这个东西,我们在转移时,如果认为\(u\)是好点,就把它的DP值乘以一个\(k\)。即:\(dp[u][i]=k\times g[i-1]\)。

时间复杂度\(O(n^2)\)。

参考代码:

  1. //problem:nflsoj489
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4. #define pb push_back
  5. #define mk make_pair
  6. #define lob lower_bound
  7. #define upb upper_bound
  8. #define fst first
  9. #define scd second
  10. typedef unsigned int uint;
  11. typedef long long ll;
  12. typedef unsigned long long ull;
  13. typedef pair<int,int> pii;
  14. namespace Fread{
  15. const int MAXN=1<<20;
  16. char buf[MAXN],*S,*T;
  17. inline char getchar(){
  18. if(S==T){
  19. T=(S=buf)+fread(buf,1,MAXN,stdin);
  20. if(S==T)return EOF;
  21. }
  22. return *S++;
  23. }
  24. }//namespace Fread
  25. #ifdef ONLINE_JUDGE
  26. #define getchar Fread::getchar
  27. #endif
  28. inline int read(){
  29. int f=1,x=0;char ch=getchar();
  30. while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
  31. while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
  32. return x*f;
  33. }
  34. inline ll readll(){
  35. ll f=1,x=0;char ch=getchar();
  36. while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
  37. while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
  38. return x*f;
  39. }
  40. /* ------ by:duyi ------ */ // dysyn1314
  41. const int MAXN=5000,MOD=998244353;
  42. inline int mod1(int x){return x<MOD?x:x-MOD;}
  43. inline int mod2(int x){return x<0?x+MOD:x;}
  44. inline void add(int &x,int y){x=mod1(x+y);}
  45. inline void sub(int &x,int y){x=mod2(x-y);}
  46. inline int pow_mod(int x,int i){int y=1;while(i){if(i&1)y=(ll)y*x%MOD;x=(ll)x*x%MOD;i>>=1;}return y;}
  47. int n,K,fac[MAXN+5],invf[MAXN+5],sz[MAXN+5],dp[MAXN+5][MAXN+5],tmp[MAXN+5];
  48. vector<int>G[MAXN+5];
  49. inline int comb(int n,int k){
  50. if(n<k)return 0;
  51. else return (ll)fac[n]*invf[k]%MOD*invf[n-k]%MOD;
  52. }
  53. void dfs(int u,int fa){
  54. sz[u]=1;
  55. dp[u][0]=1;
  56. for(int i=0;i<(int)G[u].size();++i){
  57. int v=G[u][i];
  58. if(v==fa)continue;
  59. dfs(v,u);
  60. for(int j=0;j<=sz[v]+sz[u];++j)tmp[j]=0;
  61. for(int j=0;j<=sz[v];++j){
  62. for(int k=0;k<=sz[u];++k){
  63. add(tmp[j+k],(ll)dp[v][j]*dp[u][k]%MOD*comb(j+k,j)%MOD);
  64. }
  65. }
  66. sz[u]+=sz[v];
  67. for(int j=0;j<=sz[u];++j)dp[u][j]=tmp[j];
  68. }
  69. for(int i=0;i<=sz[u];++i)tmp[i]=dp[u][i];
  70. for(int i=1;i<=sz[u];++i){
  71. dp[u][i]=0;
  72. add(dp[u][i],(ll)K*tmp[i-1]%MOD);//好点
  73. if(u!=1){
  74. sub(dp[u][i],(ll)i*tmp[i-1]%MOD);//假好点(边被反向了的坏点)
  75. add(dp[u][i],tmp[i]);//u被孤立了
  76. }
  77. }
  78. }
  79. int main() {
  80. n=read();K=read();
  81. fac[0]=1;for(int i=1;i<=n;++i)fac[i]=(ll)fac[i-1]*i%MOD;
  82. invf[n]=pow_mod(fac[n],MOD-2);
  83. for(int i=n-1;i>=0;--i)invf[i]=(ll)invf[i+1]*(i+1)%MOD;
  84. for(int i=1,u,v;i<n;++i)u=read(),v=read(),G[u].pb(v),G[v].pb(u);
  85. dfs(1,0);
  86. int ans=0;
  87. for(int i=n,s=1;i>=1;s=(ll)s*i%MOD,--i){
  88. add(ans,(ll)dp[1][i]*s%MOD);
  89. }
  90. cout<<ans<<endl;
  91. return 0;
  92. }

题解 nflsoj489 【六校联合训练 CSP #15】小D与随机的更多相关文章

  1. NFLSOJ 1072 - 【2021 六校联合训练 NOIP #1】异或(FWT+插值)

    题面传送门 一道非常不错的 FWT+插值的题 %%%%%%%%%%%% 还是那句话,反正非六校的看不到题对吧((( 方便起见在下文中设 \(n=2^d\). 首先很明显的一点是这题涉及两个维度:异或和 ...

  2. NFLSOJ 1060 - 【2021 六校联合训练 NOI #40】白玉楼今天的饭(子集 ln)

    由于 NFLSOJ 题面上啥也没有就把题意贴这儿了( 没事儿,反正是上赛季的题,你们非六校学生看了就看了,况且看了你们也没地方交就是了 题意: 给你一张 \(n\) 个点 \(m\) 条边的图 \(G ...

  3. 题解 nflsoj553 【六校联合训练 省选 #10】飞

    题目链接 我们称"简要题意"给出的三个要求分别为"条件1","条件2","条件3". 条件3长得比较丑,考虑转化一下.把 ...

  4. 题解 nflsoj550 【六校联合训练 省选 #9】序列

    题目链接 以下把值域(题面里的\(lim\))记做\(m\). 考虑求\(k\)的答案.考虑每个位置对答案的贡献,枚举位置\(i\),再枚举\(a[i]\)的值\(x\).设: \[ F(k)=\su ...

  5. HDU 5358(2015多校联合训练赛第六场1006) First One (区间合并+常数优化)

    pid=5358">HDU 5358 题意: 求∑​i=1​n​​∑​j=i​n​​(⌊log​2​​S(i,j)⌋+1)∗(i+j). 思路: S(i,j) < 10^10 & ...

  6. 2017多校联合训练2—HDU6054--Is Derek lying?(思维题)

    Is Derek lying? Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  7. 2017ACM暑期多校联合训练 - Team 2 1006 HDU 6050 Funny Function (找规律 矩阵快速幂)

    题目链接 Problem Description Function Fx,ysatisfies: For given integers N and M,calculate Fm,1 modulo 1e ...

  8. hdu 4649 Professor Tian 多校联合训练的题

    这题起初没读懂题意,悲剧啊,然后看了题解写完就AC了 题意是给一个N,然后给N+1个整数 接着给N个操作符(只有三种操作  即  或 ,与 ,和异或 |   &  ^ )这样依次把操作符插入整 ...

  9. HDU 4643 GSM 暑期多校联合训练第五场 1001

    点击打开链接 我就不说官方题解有多坑了 V图那么高端的玩意儿 被精度坑粗翔了 AC前 AC后 简直不敢相信 只能怪自己没注意题目For the distance d1 and d2, if fabs( ...

随机推荐

  1. Update(Stage4):Structured Streaming_介绍_案例

    1. 回顾和展望 1.1. Spark 编程模型的进化过程 1.2. Spark 的 序列化 的进化过程 1.3. Spark Streaming 和 Structured Streaming 2. ...

  2. 【PAT甲级】1060 Are They Equal (25 分)(需注意细节的模拟)

    题意: 输入一个正整数N(<=100),接着输入两个浮点数(可能包含前导零,对于PAT已经习惯以string输入了,这点未知),在保留N位有效数字的同时判断两个数是否相等,并以科学计数法输出. ...

  3. 最全BT磁力搜索引擎,国外最受欢迎的BT-磁力网站(整理分享,每日不断更新...)

    最全BT磁力搜索引擎索引(整理分享,每日更新) 1.海盗湾 The Pirate Bay 2.磁力天堂(BT磁力搜索下载-磁力天堂) www.btaa.xyz  (资源多,下载速度可以,建议用手机访问 ...

  4. Linux中制作静态库

    静态库生成: 1.第一步:生成.o文件 2.第二步:将所有.o文件打包 ar src  libMyTest.a  *.o 生成出libMyTest.a 3.使用: 第一种:gcc  main.c    ...

  5. Centos7618安装后常见操作

    1.查看ip ip address  或者ip add 2.查看发行版本 yum -y install redhat-lsb lsb_release -a 3.查看内核版本 uname -r cat ...

  6. 自定义 directive pagination

    学习angular过程中,对directive 不是很了解,很有必要自己写一个,以便知道它的各方面的处理方式. directive 中 scope 与 controller 交互,有三种定义策略 &q ...

  7. Verilog状态机

    以1011为例 代码如下: //1011(Meay型) module state1(clk,in,rst_n,out); input clk; input rst_n; input in; outpu ...

  8. laravel nginx下 css 和js 加载 重写规则

    server { listen 80; server_name test.hanwen.com; #charset koi8-r; #access_log logs/host.access.log m ...

  9. 一个不会coding的girl Linux日常之命令awk

    Linux日常之命令awk 参考:http://www.zsythink.net/archives/tag/awk/ 一. 命令awk简介 1. awk是一种编程语言,用于对文本和数据进行处理的 2. ...

  10. laravel API

    /** * [api] * @author Foreach * @param string $method [请求方式] * @param string $url [地址] * @param arra ...