题解

我当时连\(n^2\)的树背包都搞不明白,这道题稳稳的爆零啊= =

然后听说这道题需要FFT……我当时FFT的板子都敲不对,然后这道题就扔了

然后,我去考了thusc……好吧,令人不愉快的经历,听说我要是把这道题做了我大概就能A了D2T2……生无可恋.jpg

还有一个月,加油吧,NOI2018可能是我最后能去thu的机会了TAT

设dp[u][0 / 1][i]为以u为根的子树,没选u还是选了u,一共选了i个点

转移就是从所有子树里选出大小为i的独立集更新,转移可以类似树背包

这道题dp方程写出来卷积优化就是显然的,关键是怎么优化

我们把这个树给树链剖分了,设g[u][0 / 1][i]为u这个点除了u的重儿子以外的子树,没选u还是选了u,独立集大小为i的值(把i当成指数,把这个数组当成一个多项式)这是我们用来卷积的多项式

我们从深度最深的链开始,由于我们希望一下子算出一条链,汇总到链顶,而不关心链上每个点的dp值,用分治FFT把一条链的答案算出来,具体就是存四个多项式,记录这条链的头尾选或没选,然后合并起来

合并到父亲的时候我们对于每个点的所有轻儿子也分治乘起来,如果一个个乘起来会达到\(n ^ 2\)

分治一个链的复杂度是\(O(size(p) \log^{2} size(p))\)p是重链顶端,然后因为轻重链剖分,所以\(\sum size(p) = O(N \log N)\)复杂度为\(O(N \log^3 N)\)

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
//#define ivorysi
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define mo 974711
#define MAXN 80005
#define RG register
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
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) {putchar('-');x = -x;}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
const int MOD = 998244353,L = (1 << 18);
int W[L + 5],N,M,B[MAXN];
int siz[MAXN],dep[MAXN],fa[MAXN],son[MAXN];
int top[MAXN],Line[MAXN],tot,cnt,lsiz[MAXN],dfn[MAXN];
vector<int> f[MAXN][2],zero,g[2][MAXN];
struct node {
int to,next;
}E[MAXN * 2];
struct res_node {
vector<int> f00,f01,f10,f11;
};
int head[MAXN],sumE;
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
int inc(int a,int b) {
a = a + b;
if(a >= MOD) a -= MOD;
return a;
}
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;
}
void NTT(vector<int> &a,int len,int on) {
a.resize(len);
for(int i = 1 , j = len / 2 ; i < len - 1 ; ++i) {
if(i < j) swap(a[i],a[j]);
int k = len / 2;
while(j >= k) {
j -= k;
k >>= 1;
}
j += k;
}
for(int h = 2 ; h <= len ; h <<= 1) {
int wn = W[(L + on * L / h) % L];
for(int k = 0 ; k < len ; k += h) {
int w = 1;
for(int j = k ; j < k + h / 2 ; ++j) {
int u = a[j],t = mul(a[j + h / 2],w);
a[j] = inc(u,t);
a[j + h / 2] = inc(u,MOD - t);
w = mul(w,wn);
}
}
}
if(on == -1) {
int InvL = fpow(len,MOD - 2);
for(int i = 0 ; i < len ; ++i) a[i] = mul(a[i],InvL);
}
}
vector<int> operator - (vector<int> a,vector<int> b) {
int s = max(a.size(),b.size());
a.resize(s);b.resize(s);
vector<int> c;c.clear();
for(int i = 0 ; i < s ; ++i) c.pb(inc(a[i],MOD - b[i]));
return c;
}
vector<int> operator + (vector<int> a,vector<int> b) {
int s = max(a.size(),b.size());
a.resize(s);b.resize(s);
vector<int> c;c.clear();
for(int i = 0 ; i < s ; ++i) c.pb(inc(a[i],b[i]));
return c;
}
vector<int> operator * (vector<int> a,vector<int> b) {
int t = a.size() + b.size() - 2,T = 1;
while(T <= t) T <<= 1;
vector<int> c;c.clear();
NTT(a,T,1);NTT(b,T,1);
for(int i = 0 ; i < T ; ++i) c.pb(mul(a[i],b[i]));
NTT(c,T,-1);
if(T > M + 1) c.resize(M + 1),T = M + 1;
for(int i = T - 1 ; i > 0 ; --i) {
if(!c[i]) c.pop_back();
else break;
}
return c;
}
void dfs1(int u) {
dep[u] = dep[fa[u]] + 1;
siz[u] = 1;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u]) {
fa[v] = u;
dfs1(v);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
}
void dfs2(int u) {
dfn[u] = ++tot;Line[tot] = u;
++cnt;
if(!top[u]) top[u] = u;
if(son[u]) {
top[son[u]] = top[u];
dfs2(son[u]);
}
else {
lsiz[top[u]] = cnt;
cnt = 0;
}
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != son[u] && v != fa[u]) dfs2(v);
}
}
void Init() {
W[0] = 1;W[1] = fpow(3,(MOD - 1) / L);
for(int i = 2 ; i < L ; ++i) W[i] = mul(W[i - 1],W[1]);
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) {
read(B[i]);
f[i][0].pb(1);
f[i][1].pb(0),f[i][1].pb(B[i]);
}
int u,v;
for(int i = 1 ; i < N ; ++i) {
read(u);read(v);add(u,v);add(v,u);
}
dfs1(1);
dfs2(1);
}
res_node DC(int l,int r) {
if(l == r) {
int u = Line[l];
return (res_node){f[u][0],zero,zero,f[u][1]};
}
int mid = (l + r) >> 1;
res_node wl = DC(l,mid),wr = DC(mid + 1,r);
return (res_node){
(wl.f00 + wl.f01) * (wr.f10 + wr.f00) - wl.f01 * wr.f10,
(wl.f00 + wl.f01) * (wr.f11 + wr.f01) - wl.f01 * wr.f11,
(wl.f10 + wl.f11) * (wr.f10 + wr.f00) - wl.f11 * wr.f10,
(wl.f10 + wl.f11) * (wr.f01 + wr.f11) - wl.f11 * wr.f11,
};
}
vector<int> mul(vector<int> *g,int l,int r) {
if(l == r) return g[l];
int mid = (l + r) >> 1;
return mul(g,l,mid) * mul(g,mid + 1,r);
}
void Solve() {
res_node t;
for(int i = N ; i >= 1 ; --i) {
int u = Line[i];
if(top[u] == u) {
for(int j = dfn[u] ; j <= dfn[u] + lsiz[u] - 1 ; ++j) {
int tot = 0;
int c = Line[j];
for(int k = head[c] ; k ; k = E[k].next) {
int v = E[k].to;
if(v != fa[c] && v != son[c]) g[0][++tot] = f[v][0] + f[v][1],g[1][tot] = f[v][0];
}
if(!tot) continue;
f[c][0] = mul(g[0],1,tot);
f[c][1] = f[c][1] * mul(g[1],1,tot);
}
t = DC(dfn[u],dfn[u] + lsiz[u] - 1);
f[u][0] = t.f00 + t.f01;
f[u][1] = t.f10 + t.f11;
}
}
f[1][0].resize(M + 1);f[1][1].resize(M + 1);
out(inc(f[1][0][M],f[1][1][M]));enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}

【LOJ】#6289. 花朵的更多相关文章

  1. 13test06:花朵数

    #include<iostream> using namespace std; #define N a//定义宏时后面不加:否则会把':'一起定义为宏. int getP(int,int) ...

  2. Flash-使用变形面板制作花朵

    在Flash中利用"变形"面板的"重置选取和变形"button(在变形面板右下角),能够自己主动将对象进行创造性变形地画图 步骤: (1)先导入一幅图像 (2) ...

  3. [Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086

    额... 首先,看到这道题,第一想法就是二分答案+线段树... 兴高采烈的认为我一定能AC,之后发现n是500000... nlog^2=80%,亲测可过... 由于答案是求满足题意的最大长度-最小长 ...

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

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

  5. Loj #3096. 「SNOI2019」数论

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

  6. Loj #3093. 「BJOI2019」光线

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

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

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

  8. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  9. Loj #2331. 「清华集训 2017」某位歌姬的故事

    Loj #2331. 「清华集训 2017」某位歌姬的故事 IA 是一名会唱歌的女孩子. IOI2018 就要来了,IA 决定给参赛选手们写一首歌,以表达美好的祝愿.这首歌一共有 \(n\) 个音符, ...

随机推荐

  1. CSS文字溢出部分自动用"..."代替

    CSS文字溢出部分自动用"..."代替 如html部分: <h4><马尔代夫双鱼岛Olhuveli4 晚6 日自助游></h4> <p&g ...

  2. jquery读取html5的data-属性

    前端代码的工作无非就是接收后端发来的数据,展示到前端页面:又或者,给无数的按钮,图片,段落等绑定各种事件.那么我们在绑定事件是需要拿取HTML页面的元素,以及在拿取的元素给定各式各样的自定义属性.当需 ...

  3. 基于JavaSE阶段的IO流详解

    1.IO流基本概述 在Java语言中定义了许多针对不同的传输方式,最基本的就是输入输出流(俗称IO流),IO流是属于java.io包下的内容,在JavaSE阶段主要学下图所示的: 其中从图中可知,所有 ...

  4. [DeeplearningAI笔记]序列模型1.1-1.2序列模型及其数学符号定义

    5.1循环序列模型 觉得有用的话,欢迎一起讨论相互学习~Follow Me 1.1什么是序列模型 在进行语音识别时,给定了一个输入音频片段X,并要求输出片段对应的文字记录Y,这个例子中的输入和输出都输 ...

  5. 如何识别字符串是否是UTF-8编码的

    我们先要弄明白原始字符串里的字符用的是何种编码方式,运行如下 string tmp = "你好world"; for(int i=0;i<tmp.size();++i) { ...

  6. HDU 6206 青岛网络赛1001 高精度 简单几何

    给出的数据1e12规模,常规判点是否在圆范围内肯定要用到半径,求得过程中无法避免溢出,因此用JAVA自带的浮点大数运算,和个ZZ一样比赛中eclipse出现问题,而且太久没写JAVA语法都不清楚变量忘 ...

  7. 什么是Qt Widget?

    Qt帮助文档如此解释: The user interface contains visual elements that are called widgets in Qt. Examples of w ...

  8. python 文字转语音包pyttsx安装出错解决方法

    pyttsx的python的文字转语音的包,但是pyttsx的官方网站上资源只更新2012年,所以在py3中使用pip install pyttsx或者下载安装包进行安装时,虽然可以安装成功,但是im ...

  9. 朋友封装的一个ASP.NET上传文件的方法

    朋友做了asp.net开发多年,做了这个,自我感觉封装得还不错!!! 代码如下: #region 上传文件的方法 /// <summary> /// 上传文件方法 /// </sum ...

  10. bzoj 1934最小割

    比较显然的最小割的题,增加节点source,sink,对于所有选1的人我们可以(source,i,1),选0的人我们可以(i,sink,1),然后对于好朋友我们可以连接(i,j,1)(j,i,1),然 ...