LOJ#3102. 「JSOI2019」神经网络

首先我们容易发现就是把树拆成若干条链,然后要求这些链排在一个环上,同一棵树的链不相邻

把树拆成链可以用一个简单(但是需要复杂的分类讨论)的树背包实现

\(dp[u][j][0/1/2]\)表示第\(u\)个点已经选了\(j\)条链,0是两个不同子树的链拼到一起,1是只有1个点,2是有一条至少有两个点的链

通过这个我们可以求一个\(f[k]\)表示把这棵树分成\(k\)条链有几种情况

环排列可以通过全排列除以排列长度得到

我们设把\(k\)条链分成\(h\)个小块,这样我们至少有了\(k - h\)对点同一棵树且相邻,容斥系数乘上\((-1)^{k - h}\),对于全排列来说,我们还需要除以\(h!\)

所以列出一个这样的EGF

\(f[k]k!\binom{k - 1}{h - 1} \frac{x^{h}}{h!}\)

就可以卷积了

然后对于答案的\(x^{h}\)乘上\((h - 1)!\)因为是环排

就可以得到答案

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define ba 47
#define MAXN 5005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 +c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
const int MOD = 998244353,MAXL = (1 << 15);
int W[MAXL + 5];
int fac[100005],invfac[100005];
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
void update(int &x,int y) {
x = inc(x,y);
}
int fpow(int x,int c) {
int res = 1,t = x;
while(c) {
if(c & 1) res = mul(res,t);
t = mul(t,t);
c >>= 1;
}
return res;
}
int C(int n,int m) {
if(n < m) return 0;
else return mul(fac[n],mul(invfac[m],invfac[n - m]));
}
void NTT(vector<int> &f,int l,int on) {
f.resize(l);
for(int i = 1,j = l >> 1 ; i < l - 1 ; ++i) {
if(i < j) swap(f[i],f[j]);
int k = l >> 1;
while(j >= k) {
j -= k;
k >>= 1;
}
j += k;
}
for(int h = 2 ; h <= l ; h <<= 1) {
int wn = W[(MAXL + on * MAXL / h) % MAXL];
for(int k = 0 ; k < l ; k += h) {
int w = 1;
for(int j = k ; j < k + h / 2 ; ++j) {
int u = f[j],t = mul(w,f[j + h / 2]);
f[j] = inc(u,t);
f[j + h / 2] = inc(u,MOD - t);
w = mul(w,wn);
}
}
}
if(on == -1) {
int invL = fpow(l,MOD - 2);
for(int i = 0 ; i < l ; ++i) f[i] = mul(f[i],invL);
}
}
vector<int> operator * (vector<int> a,vector<int> b) {
vector<int> c;
int l = 1;
while(l <= a.size() - 1 + b.size() - 1) l <<= 1;
NTT(a,l,1);NTT(b,l,1);
c.resize(l);
for(int i = 0 ; i < l ; ++i) c[i] = mul(a[i],b[i]);
NTT(c,l,-1);
int s = c.size() - 1;
while(s > 0) {
if(c[s] == 0) {c.pop_back();--s;}
else break;
}
return c;
}
void Init() {
W[0] = 1;W[1] = fpow(3,(MOD - 1) / MAXL);
for(int i = 2 ; i < MAXL ; ++i) W[i] = mul(W[i - 1],W[1]);
fac[0] = 1;
for(int i = 1 ; i <= 100000 ; ++i) fac[i] = mul(fac[i - 1],i);
invfac[100000] = fpow(fac[100000],MOD - 2);
for(int i = 99999 ; i >= 0 ; --i) invfac[i] = mul(invfac[i + 1],i + 1);
}
int M,K;
struct node {
int to,next;
}E[100005];
int head[5005],sumE,siz[5005];
int dp[5005][5005][3],g[5005][3],f[5005],all;
vector<int> z,ans;
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
void dfs(int u,int fa) {
dp[u][0][1] = 1;
siz[u] = 1;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa) {
dfs(v,u);
for(int j = 0 ; j <= siz[u] + siz[v] ; ++j) memset(g[j],0,sizeof(g[j]));
for(int j = 0 ; j <= siz[u] ; ++j) {
for(int h = 0 ; h <= siz[v] ; ++h) {
int t0 = inc(dp[v][h][1],mul(dp[v][h][2],2));
int t1 = inc(dp[v][h][1],dp[v][h][2]);
update(g[j + h][0],mul(dp[u][j][0],dp[v][h][0]));
update(g[j + h + 1][0],mul(dp[u][j][0],t0));;
update(g[j + h][1],mul(dp[u][j][1],dp[v][h][0]));
update(g[j + h + 1][1],mul(dp[u][j][1],t0));
update(g[j + h][2],mul(dp[u][j][1],t1));
update(g[j + h][2],mul(dp[u][j][2],dp[v][h][0]));
update(g[j + h + 1][2],mul(dp[u][j][2],t0));
update(g[j + h + 1][0],mul(dp[u][j][2],mul(2,t1)));
}
}
siz[u] += siz[v];
for(int j = 0 ; j <= siz[u] ; ++j) {
for(int h = 0 ; h < 3 ; ++h) {
dp[u][j][h] = g[j][h];
}
}
}
}
if(!fa) {
memset(f,0,sizeof(f));
for(int j = 0 ; j <= siz[1] ; ++j) {
update(f[j],dp[1][j][0]);
update(f[j + 1],dp[1][j][1]);
update(f[j + 1],mul(2,dp[1][j][2]));
}
}
}
void Solve() {
read(M);
ans.pb(1);
for(int i = 1 ; i <= M ; ++i) {
sumE = 0;
memset(head,0,sizeof(head));
memset(siz,0,sizeof(siz));
for(int j = 0 ; j <= K ; ++j) {
for(int h = 0 ; h <= K ; ++h) {
memset(dp[j][h],0,sizeof(dp[j][h]));
}
}
read(K);
all += K;
int a,b;
for(int j = 1 ; j < K ; ++j) {
read(a);read(b);
add(a,b);add(b,a);
}
dfs(1,0);
z.clear();
z.resize(K + 1);
for(int j = K ; j >= 1 ; --j) {
int a = mul(f[j],fac[j]);
for(int h = j ; h >= 1 ; --h) {
int t = mul(a,C(j - 1,h - 1));
if((j - h) & 1) t = MOD - t;
update(z[h],t);
}
}
for(int j = 0 ; j <= K ; ++j) z[j] = mul(z[j],invfac[j]);
ans = ans * z;
}
int res = 0;
for(int i = 1 ; i <= all ; ++i) {
update(res,mul(ans[i],fac[i - 1]));
}
out(res);enter;
}
int main(){
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}

【LOJ】#3102. 「JSOI2019」神经网络的更多相关文章

  1. Loj #3102. 「JSOI2019」神经网络

    Loj #3102. 「JSOI2019」神经网络 题目背景 火星探险队发现,火星人的思维方式与人类非常不同,是因为他们拥有与人类很不一样的神经网络结构.为了更好地理解火星人的行为模式,JYY 对小镇 ...

  2. LOJ #3103. 「JSOI2019」节日庆典

    题意 给定字符串 \(S\) ,对于 \(S\) 的每个前缀 \(T\) 求 \(T\) 所有循环同构串的字典序最小的串,输出其起始下标.(如有多个输出最靠前的) \(|S| \le 3 \times ...

  3. LOJ3102. 「JSOI2019」神经网络 [DP,容斥,生成函数]

    传送门 思路 大部分是感性理解,不保证完全正确. 不能算是神仙题,但我还是不会qwq 这题显然就是求:把每一棵树分成若干条链,然后把链拼成一个环,使得相邻的链不来自同一棵树,的方案数.(我才不告诉你们 ...

  4. 【LOJ】#3103. 「JSOI2019」节日庆典

    LOJ#3103. 「JSOI2019」节日庆典 能当最小位置的值一定是一个最小后缀,而有用的最小后缀不超过\(\log n\)个 为什么不超过\(\log n\)个,看了一下zsy的博客.. 假如\ ...

  5. 【LOJ】#3101. 「JSOI2019」精准预测

    LOJ#3101. 「JSOI2019」精准预测 设0是生,1是死,按2-sat连边那么第一种情况是\((t,x,1) \rightarrow (t + 1,y,1)\),\((t + 1,y, 0) ...

  6. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  7. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  8. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  9. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

随机推荐

  1. rxjs与vue

    原创文章,转载请注明出处 使用vue-rx插件将vue和rxjs联系起来 在main.js中将vue-rx注入vue中 import Vue from 'vue' import App from '. ...

  2. Luogu5327【ZJOI2019】语言【树上差分,线段树合并】

    题目大意 给定一棵$n$个节点的树,维护$n$个集合,一开始第$i$个集合只有节点$i$.有$m$个操作,每次操作输入一个$(u,v)$,表示将$(u,v)$这条链上所有点所属的集合合并.求有多少个无 ...

  3. Break Standard Weight (ZOJ 3706)

    Problem The balance was the first mass measuring instrument invented. In its traditional form, it co ...

  4. gitlab 配置.ssh实现免密登陆

    首次配置gitlab的.ssh时 安装gitbash 通过gitbash 配置.ssh 打开gitbash,输入如下命令生成ssh,邮箱换成自己的 ssh-keygen -t rsa -C " ...

  5. JAVA RPC (十) nio服务端解析

    源码地址:https://gitee.com/a1234567891/koalas-rpc 企业生产级百亿日PV高可用可拓展的RPC框架.理论上并发数量接近服务器带宽,客户端采用thrift协议,服务 ...

  6. Robot Framework(十九) 附录

    6附录 6.1测试数据中的所有可用设置 6.1.1设置表 Setting表用于导入测试库,资源文件和变量文件,以及定义测试套件和测试用例的元数据.它可以包含在测试用例文件和资源文件中.请注意,在资源文 ...

  7. 2015 ACM Arabella Collegiate Programming Contest

    题目链接:https://vjudge.net/contest/154238#overview. ABCDE都是水题. F题,一开始分类讨论,结果似乎写挫了,WA了一发.果断换并查集上,A了. G题, ...

  8. HDU 4374 One hundred layer(单调队列DP)

    题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=116242#problem/E 题意:差不多就是男人勇下百层的游戏.从第一层到最 ...

  9. Python语法 - 生成器

    生成器基本概念 1 生成器不会把结果保存在一个系列中,而是保存生成器的状态,在每次进行迭代时返回一个值,直到遇到StopIteration异常结束 2 生成器表达式能做的事情列表解析基本都能处理,只不 ...

  10. MATLAB实现模糊控制

    一.简介 MATLAB软件有提供一个模糊推理系统编辑器,利用模糊工具箱在matlab命令窗口输入Fuzzy命令进入模糊控制编辑环境 二.主要步骤 1.接受输入变量 2.输入变量模糊化 3.利用模糊规则 ...