稍微转化一下,就是找所有和原树差距不超过k的不同构树的个数

一个挺trick的想法是:

由于矩阵树定理的行列式的值是把邻接矩阵数值看做边权的图的所有生成树的边权乘积之和

那么如果把不存在于原树中的边的边权设为x,做矩阵树定理得到n-1次的多项式第i次项系数就是选择新选择i个边的方案数!

带着x不好做,x=1~n带入,然后插值即可

O(n^4)

开始碾标算了:

还是可以树形DP,经典的树形DP套路难办的原因是不知道干掉的子树接在哪里

所以我们干脆先不管接在哪里,先都砍断

一个公式:

https://rqy.moe/Solutions/bzoj5475/

证明导数第二步有点生成函数的思想了

对于拆成k个连通块,方案数可以直接算

设f[i][j][k],以i为根子树保留j条边,和i相连的连通块sz为k的方案数。枚举子树保留边数和sz就可以愉快转移了

但是会算重

如果直接乘上n^(k-2)可能会把断的边连回去,不止保留了j个,并且同一个方案可能因为保留的不同的j个计算多次!

不慌不慌

一切都是因为实际上可能连回去保留了不止j个,我们钦定了j个,其他随便选的方案数是f,

枚举具体保留了几个,可以二项式反演

$f[t]=\sum_{k=t}^{n} C(k,t)*ans[k]$

ans表示恰好保留了k个

没了

O(n^3)

进一步优化!

$\Pi a_i$有组合意义,就是对于k个连通块,我们每个连通块恰好选择一个点的方案数!

f[i][j][0/1],表示,,,,,i这个连通块内有没有选择点,总方案数

愉快转移,断边必须y选择。

代码

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;x=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=;
const int mod=;
int n,k;
int qm(int x,int y){
int ret=;while(y){
if(y&) ret=(ll)ret*x%mod;x=(ll)x*x%mod;
y>>=;
}return ret;
}
struct node{
int nxt,to;
}e[*N];
int hd[N],cnt;
int ad(int x,int y){
return x+y>=mod?x+y-mod:x+y;
}
void add(int x,int y){
e[++cnt].nxt=hd[x];
e[cnt].to=y;
hd[x]=cnt;
}
int sz[N];
int f[N][N][];
int C[N][N];
ll ans[N],dp[N];
void dfs(int x,int fa){
sz[x]=;
f[x][][]=f[x][][]=;
int g[][N][];
memset(g[],,sizeof g[]);
//memset(g,0,sizeof g);
g[][][]=g[][][]=;
int tmp=;
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
dfs(y,x);
tmp^=;
//for(reg j=0;j<sz[x]+sz[y];++j) g[tmp][j][0]=g[tmp][j][1]=0;
memset(g[tmp],,sizeof g[tmp]);
for(reg j=;j<sz[x];++j){
for(reg k=;k<sz[y];++k){
g[tmp][j+k][]=ad(g[tmp][j+k][],(ll)g[tmp^][j][]*f[y][k][]%mod);
g[tmp][j+k][]=ad(g[tmp][j+k][],(ll)g[tmp^][j][]*f[y][k][]%mod); g[tmp][j+k+][]=ad(g[tmp][j+k+][],(ll)g[tmp^][j][]*f[y][k][]%mod);
g[tmp][j+k+][]=ad(g[tmp][j+k+][],ad((ll)g[tmp^][j][]*f[y][k][]%mod,(ll)g[tmp^][j][]*f[y][k][]%mod));
}
}
sz[x]+=sz[y];
}
//cout<<" f "<<x<<endl;
for(reg j=;j<sz[x];++j) {
f[x][j][]=g[tmp][j][],f[x][j][]=g[tmp][j][];
//cout<<j<<" n0 "<<" : "<<f[x][j][0]<<" n1 "<<f[x][j][1]<<endl;
}
}
int main(){
rd(n);rd(k);
if(k==){
puts("");return ;
}
int x;
for(reg i=;i<=n;++i){
rd(x);++x;
add(i,x);add(x,i);
}
dfs(,);
for(reg j=;j<n;++j) {
if(j!=n-) dp[j]=(ll)f[][j][]*qm(n,n-j-);
else dp[j]=;
}
ans[n-]=dp[n-];
C[][]=;
for(reg i=;i<=n;++i){
C[i][]=;
for(reg j=;j<=n;++j){
C[i][j]=(C[i-][j-]+C[i-][j])%mod;
}
}
ll op=ans[n-];
for(reg i=n-;i>=n-k-;--i){
// cout<<" ii "<<i<<" : "<<dp[i]<<endl;
for(reg j=i+;j<n;++j){
dp[i]=(dp[i]+mod-(ll)C[j][i]*ans[j]%mod)%mod;
}
ans[i]=dp[i];
op=(op+dp[i])%mod;
}
printf("%lld",op);
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2019/3/4 19:02:40
*/

思路:

矩阵树:新加k条新边,为了控制边数,所以用x表示边权得到方案数,插值也很漂亮

DP:直接DP难写,受prufer序列的推论启发,考虑对于连通块直接统计,然后二项式反演去重

  组合意义的优化,类似于:[NOI2009]管道取珠

省选模拟赛第四轮 B——O(n^4)->O(n^3)->O(n^2)的更多相关文章

  1. 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解

    今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...

  2. @省选模拟赛03/16 - T3@ 超级树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...

  3. 3.28 省选模拟赛 染色 LCT+线段树

    发现和SDOI2017树点涂色差不多 但是当时这道题模拟赛的时候不会写 赛后也没及时订正 所以这场模拟赛的这道题虽然秒想到了LCT和线段树但是最终还是只是打了暴力. 痛定思痛 还是要把这道题给补了. ...

  4. NOI2019省选模拟赛 第五场

    爆炸了QAQ 传送门 \(A\) \(Mas\)的童年 这题我怎么感觉好像做过--我记得那个时候还因为没有取\(min\)结果\(100\to 0\)-- 因为是个异或我们肯定得按位考虑贡献了 把\( ...

  5. NOI2019省选模拟赛 第六场

    传送门 又炸了-- \(A\) 唐时月夜 不知道改了什么东西之后就\(A\)掉了\(.jpg\) 首先,题目保证"如果一片子水域曾经被操作过,那么在之后的施法中,这片子水域也一定会被操作&q ...

  6. 省选模拟赛 arg

    1 arg (arg.cpp/in/out, 1s, 512MB)1.1 Description给出一个长度为 m 的序列 A, 请你求出有多少种 1...n 的排列, 满足 A 是它的一个 LIS. ...

  7. 5.10 省选模拟赛 拍卖 博弈 dp

    LINK:拍卖 比赛的时候 前面时间浪费的有点多 写这道题的时候 没剩多少时间了. 随便设了一个状态 就开始做了. 果然需要认真的思考.其实 从我的状态的状态转移中可以看出所有的结论. 这里 就不再赘 ...

  8. 5.5 省选模拟赛 B Permutation 构造 贪心

    LINK:Permutation 对于这种构造神题 我自然是要补的.为啥就我没想出来哇. 30分还是很好写的 注意8!实际上很小 不需要爆搜 写bfs记录状态即可.至于判断状态是否出现与否 可以开ma ...

  9. 省选模拟赛 4.26 T1 dp 线段树优化dp

    LINK:T1 算是一道中档题 考试的时候脑残了 不仅没写优化 连暴力都打挂了. 容易发现一个性质 那就是同一格子不会被两种以上的颜色染.(颜色就三种. 通过这个性质就可以进行dp了.先按照左端点排序 ...

随机推荐

  1. Mvc_后端通用验证

    namespace Web.Mvc.Extensions { #region 验证基类 /// <summary> /// 通用验证基类 /// </summary> publ ...

  2. Linux下部署SSH登录时的二次身份验证环境记录(利用Google Authenticator)

    一般来说,使用ssh远程登录服务器,只需要输入账号和密码,显然这种方式不是很安全.为了安全着想,可以使用GoogleAuthenticator(谷歌身份验证器),以便在账号和密码之间再增加一个验证码, ...

  3. windows如何查看电脑开关机记录

    如何查看电脑开关机记录 (一)如果你只是想查看一下,从昨天关机到今天开机之间有没有人使用我的计算机,在“开始”菜单的运行”中输入“eventvwr.msc”,或者是按下"开始菜单" ...

  4. Python数据类型-7

    什么数据类型. int 1,2,3用于计算. bool:True,False,用户判断. str:存储少量数据,进行操作 'fjdsal' '二哥','`13243','fdshklj' '战三,李四 ...

  5. BugPhobia团队篇章:团队管理与Github源代码管理说明

    0x00:序言 To the searching tags, you may well fall in love withhttp://xueba.nlsde.buaa.edu.cn/ 再见,无忧时光 ...

  6. Linux内核分析作业 NO.6

    进程的描述和进程的创建 于佳心  原创作品转载请注明出处  <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-100002900 ...

  7. 正则表达式(java)

    概念: 正则表达式,又称规则表达式.(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念. 正则表通常被用来检索.替换那些符合某个模式( ...

  8. Minor GC vs Major GC vs Full GC

    http://www.importnew.com/15820.html https://plumbr.io/blog/garbage-collection/minor-gc-vs-major-gc-v ...

  9. Disabling Chrome cache for website development

    https://stackoverflow.com/questions/5690269/disabling-chrome-cache-for-website-development https://s ...

  10. Selenium IDE 宏 试用 一例

    本质是宏(Macro)理念 Marco概念的广泛应用: 1.Office的Excel里的任何操作的 可以都可以用VBA编程记录下宏,然后把记录的宏,可以回放.当然也可以生成代码,比如给Excel设置单 ...