题意:给一棵树,一次操作定义为删掉一条树边再加一条边,并且满足加完边后这还是一棵树,问在进行不超过$k$次操作后能构造出多少种不同的树

首先...矩阵树定理在边有边权的时候同样适用,这时可以把它看成重边,此时直接按原方法求得的是所有生成树的边权乘积之和

所以我们可以把这棵树补成一个完全图,令补上去的边边权为$x$,那么答案就是求出来的多项式的$0\cdots k$次系数之和

直接带着多项式做当然不行,所以我们就用单位根作为$x$,求值后IDFT回去即可

我的代码在$k=n-1$时会错...?

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=998244353;
int mul(int a,int b){return a*(ll)b%mod;}
int ad(int a,int b){return(a+b)%mod;}
int de(int a,int b){return(a-b)%mod;}
int pow(int a,int b){
	int s=1;
	while(b){
		if(b&1)s=mul(s,a);
		a=mul(a,a);
		b>>=1;
	}
	return s;
}
int rev[64],N,iN;
void pre(int n){
	int i,k;
	for(N=1,k=0;N<=n;N<<=1)k++;
	for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
	iN=pow(N,mod-2);
}
void ntt(int*a,int on){
	int i,j,k,t,w,wn;
	for(i=0;i<N;i++){
		if(i<rev[i])swap(a[i],a[rev[i]]);
	}
	for(i=2;i<=N;i<<=1){
		wn=pow(3,on==1?(mod-1)/i:mod-1-(mod-1)/i);
		for(j=0;j<N;j+=i){
			w=1;
			for(k=0;k<i>>1;k++){
				t=mul(w,a[i/2+j+k]);
				a[i/2+j+k]=de(a[j+k],t);
				a[j+k]=ad(a[j+k],t);
				w=mul(w,wn);
			}
		}
	}
	if(on==-1){
		for(i=0;i<N;i++)a[i]=mul(a[i],iN);
	}
}
int d[64],tr[64][64],g[64][64],n;
int gauss(int n){
	int i,j,k,t,c,s;
	s=1;
	for(i=1;i<=n;i++){
		t=pow(g[i][i],mod-2);
		for(j=i+1;j<=n;j++){
			c=mul(t,g[j][i]);
			for(k=i;k<=n;k++)g[j][k]=de(g[j][k],mul(c,g[i][k]));
		}
		s=mul(s,g[i][i]);
	}
	return s;
}
int solve(int x){
	int i,j;
	memset(g,0,sizeof(g));
 	for(i=1;i<=n;i++)g[i][i]=ad(d[i],mul(n-1-d[i],x));
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++){
			if(i!=j){
				if(tr[i][j])
					(g[i][j]-=1)%=mod;
				else
					(g[i][j]-=x)%=mod;
			}
		}
	}
	return gauss(n-1);
}
int po[64];
int main(){
	int k,i,x,s;
	scanf("%d%d",&n,&k);
	if(k==n-1){
		printf("%d",pow(n,n-2));
		return 0;
	}
	for(i=2;i<=n;i++){
		scanf("%d",&x);
		x++;
		tr[x][i]=tr[i][x]=1;
		d[x]++;
		d[i]++;
	}
	pre(n);
	for(i=0;i<N;i++)po[i]=solve(pow(3,(mod-1)/N*i));
	ntt(po,-1);
	s=0;
	for(i=0;i<=k;i++)s=ad(s,po[i]);
	printf("%d",ad(s,mod));
}

[xsy2289]B的更多相关文章

随机推荐

  1. HDU 2639 Bone Collector II (dp)

    题目链接 Problem Description The title of this problem is familiar,isn't it?yeah,if you had took part in ...

  2. It is possible that this issue is resolved by uninstalling an existi

    使用真机连接Android Studio测试时出现这样的错误: 解决方法: 设置Android Studio 中Instant Run中的选项为不选中 根据以下路径,找到Instant Run中的选项 ...

  3. Java 关于微信公众号支付总结附代码

    很多朋友第一次做微信支付的时候都有蒙,但当你完整的做一次就会发现其实并没有那么难 业务流程和应用场景官网有详细的说明:https://pay.weixin.qq.com/wiki/doc/api/js ...

  4. 【Windows使用笔记】Windows日常使用软件

    整理一些对于我来说日常使用的Windows软件. 排名不分先后,仅凭我想起来的顺序! 1 MadAppLauncher 这个对我来说非常需要了. 使用它可以快速启动日常常用的软件,非常快捷高效.一般来 ...

  5. 【Matlab】绘制饼状统计图

    a=tabulate(b); % b为需要绘制饼图的原始数据列,生成新的一个矩阵a label={'1','2','3'} % 设定饼图每块扇形代表的内容 percent=num2str(a(:,3) ...

  6. LINUX-内核-中断分析-中断向量表(3)-arm【转】

    转自:http://blog.csdn.net/haolianglh/article/details/51986987 arm中断概念 在<ARM体系结构与编程>第9章中说到,ARM 中有 ...

  7. Linux内核空间内存申请函数kmalloc、kzalloc、vmalloc的区别【转】

    转自:http://www.th7.cn/system/lin/201606/167750.shtml 我们都知道在用户空间动态申请内存用的函数是 malloc(),这个函数在各种操作系统上的使用是一 ...

  8. python基础===self的理解

    self是类的实例 self有点类似java中的this,无实际意义.但是约定俗成的都是用self表示类的实例 class A: def func(self): print(self) #指向的是类的 ...

  9. 经典卷积网络模型 — LeNet模型笔记

    LeNet-5包含于输入层在内的8层深度卷积神经网络.其中卷积层可以使得原信号特征增强,并且降低噪音.而池化层利用图像相关性原理,对图像进行子采样,可以减少参数个数,减少模型的过拟合程度,同时也可以保 ...

  10. vue 文件引入

    直接 <script> 引入 直接下载并用 <script> 标签引入,Vue 会被注册为一个全局变量.重要提示:在开发时请用开发版本,遇到常见错误它会给出友好的警告. 开发环 ...