题目大意

有一棵\(n\)(\(n\leq 1666\))个点的树,有点权\(d_i\),点权最大值为\(w\)(\(w\leq 1666\))。给出\(k\)(\(k\leq n\)),定义一个选择连通块的方案的权值为该连通块第\(k\)大的点权,如果该连通块大小\(<k\),那么该方案的权值为0。求所有选择连通块的方案的权值之和。

题解

考虑暴力:

设\(f(S,k)\)表示连通块\(S\)中第\(k\)大的点权,那么答案就是\(\sum\limits_{i=1}^{w}i\times(\sum\limits_{S\in [1,n]}[f(S,k)=i])\);

前面乘的\(i\)看上去很烦,考虑把\([f(S,k)=i]\)算\(i\)遍,就有该式=\(\sum\limits_{i=1}^w\sum\limits_{j=1}^i\sum\limits_{S\in[1,n]}[f(S,k)=j]\);

把\(j\)拿到前面,就有该式=\(\sum\limits_{j=1}^w\sum\limits_{S\in[1,n]}[f(S,k)\geq j]\);

设\(c(S,i)\)表示连通块\(S\)中大于等于\(i\)的点权的个数,那么当 \([f(S,k)\geq i]\) 时一定有\([c(S,i)\geq k]\),式子变成\(\sum\limits_{i=1}^w\sum\limits_{S\in[1,n]}[c(S,i)\geq k]\)=\(\sum\limits_{i=1}^w\sum\limits_{j=k}^n\sum\limits_{S\in[1,n]}[c(S,i)==j]\);

就可以设\(h(i,j,x)\)表示 以\(i\)为深度连通块最小的点 且 大于等于\(j\)的数的个数为\(x\) 的连通块个数,就有答案=\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^w\sum\limits_{x=k}^n h(i,j,x)\);

\(h(i,j,x)\)的转移为:当\(d_i<j\)时,\(h(i,j,x)=\prod\limits_{v\in son(i),\sum y_v=x}h(v,j,y_v)\);当\(d_i\geq x\)时,\(h(i,j,x)=\prod\limits_{v\in son(i),\sum y_v=x-1}h(v,j,y_v)\)。

以上的暴力做法转移过程类似树上背包,所以它的时间复杂度是\(\Theta(n^2\times w)\)的。

考虑设多项式\(F_{i,j}(x)=\sum\limits_{a=0}^n h(i,j,a)\times x^n\),那么转移会变成卷。

设多项式\(G_{i,j}(x)=\sum\limits_{v\in i的子树}F_{v,j}(x)\),\(H_i(x)=\sum\limits_{j=1}^w G_{i,j}(x)\),那么\(H_1\)的\(k\)次项系数到第\(n\)次项系数就会是答案。

发现在进行儿子到父亲的转移时,对于\(j\in[1,w]\),\(f(i,j,a)\)的转移大同小异,考虑对于每个点\(i\)同时维护\(F_{i,j}(x)\)这些多项式。

直接维护多项式不太可行。考虑将\(x=1,2,...,n+1\)代入,用\(y=F_{i,j}(x)\)来代表这个多项式进行点值的计算,最后得到\(H_1(1),...,H_1(n+1)\),再用拉格朗日插值还原出\(H_1(x)\)。

初始值:当\(d_i\geq j\)时,有\(F_{i,j}=x\)(即\(f(i,j,1)=1\));当\(d_i< j\)时,有\(F_{i,j}=1\)(即\(f(i,j,0)=1\));

在从\(i\)的儿子\(v\)转移到\(i\)时要做这么几件事:\(F_{i,j}卷=(F_{v,j}+1),G_{i,j}+=G_{v,j}\);

考虑完所有\(i\)的儿子到\(i\)的转移后,还应有:\(G_{i,j}+=F_{i,j}\)。

发现\(F_{i,j}卷=(F_{v,j}+1)\)不太好办,可以在计算完\(F_{i,j},G_{i,j}\)后,令\(F_{i,j}+=1\)。

以上过程可以用线段树维护,设初始值相当于区间修改,其他的相当于全局加,从\(i\)的儿子转移到\(i\)相当于合并两棵线段树上的标记。

具体地,要维护标记\((a,b,c,d)\)表示\(F=a\times F+b,G=c\times F+d+G\)。

考虑标记的叠加:假设一个点先被标记了\((a_0,b_0,c_0,d_0)\),又被标记了\((a_1,b_1,c_1,d_1)\),就相当于\(F=a_1\times(a_0\times F+b_0)+b_1\)=\((a_1\times a_0)\times F+(a_1\times b_0+b_1)\),\(G=c_1\times(a_0\times F+b_0)+d_1+c_0\times F+d_0+G\)=\((c_1\times a_0+c_0)\times F+(c_1\times b_0+d_1+d_0)+G\),也就是它们的标记合并起来就是\((a_1\times a_0,a_1\times b_0+b_1,c_1\times a_0+c_0,c_1\times b_0+d_1+d_0)\)。

标记叠加的性质:观察可得标记的叠加不满足交换律;假设一个点先被标记了\((a_0,b_0,c_0,d_0)\),又被标记了\((a_1,b_1,c_1,d_1)\),又被标记了\((a_2,b_2,c_2,d_2)\),可以通过计算\((a_0,b_0,c_0,d_0)+(a_1,b_1,c_1,d_1)+(a_2,b_2,c_2,d_2)\)和\((a_0,b_0,c_0,d_0)+((a_1,b_1,c_1,d_1)+(a_2,b_2,c_2,d_2))\)来证明其满足结合律,因此可以在线段树上打标记,合并时合并标记。

整个流程是:枚举\(x\)取1到\(n+1\)(其实是随便\(n+1\)个数),从一号点(其实是随便一个点)开始DFS。每走到一个点,区间加初始值,走该点的每个儿子,走完每个儿子后线段树合并,合并后可以回收不用的点。走完所有儿子后进行一些小的处理(如\(G+=F,F++\))。把每个点走完后,计算\(H_1(x)=\sum_{j=1}^w G_{1,j}(x)\)。枚举完\(x\)后,得到\(n+1\)个\(H_1\)的点值,做一遍拉格朗日插值得到\(H_1\)每一项的系数,计算\(k\)次项至\(n\)次项系数的和。

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define LL long long
#define maxn 1677
#define ls son[u][0]
#define rs son[u][1]
#define Ls(u) son[u][0]
#define Rs(u) son[u][1]
#define UI unsigned int
#define mi (l+r>>1)
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(UI x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
const UI mod=64123;
UI ans,f[maxn],qy[maxn],b[maxn];
int n,K,w,d[maxn],rt[maxn],fir[maxn],nxt[maxn<<1],v[maxn<<1],cnt,son[maxn<<6][2],rec[maxn<<6],tpr,cntnd;
struct node{UI a,b,c,d;}tr[maxn<<6];
UI mo(UI x){return x>=mod?x-mod:x;}
void ade(int u1,int v1){v[cnt]=v1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
UI mul(UI x,int y){UI res=1;while(y){if(y&1)res=res*x%mod;x=x*x%mod,y>>=1;}return res;}
void pu(node & x,node y,node z)
{
x.a=y.a*z.a%mod;
x.b=mo(z.a*y.b%mod+z.b);
x.c=mo(z.c*y.a%mod+y.c);
x.d=mo((z.c*y.b%mod+z.d)+y.d);
}
node getnd(UI a,UI b,UI c,UI d){node tmp;tmp.a=a,tmp.b=b,tmp.c=c,tmp.d=d;return tmp;}
int newnd(){int u=tpr?rec[tpr--]:++cntnd;tr[u].a=1,tr[u].b=tr[u].c=tr[u].d=ls=rs=0;return u;}
void pd(int u)
{
if(!ls)ls=newnd();
pu(tr[ls],tr[ls],tr[u]);
if(!rs)rs=newnd();
pu(tr[rs],tr[rs],tr[u]);
tr[u].a=1,tr[u].b=tr[u].c=tr[u].d=0;
}
int add(int u,int l,int r,int x,int y,node k)
{
if(!u)u=newnd();
if(x<=l&&r<=y){pu(tr[u],tr[u],k);return u;}
pd(u);
if(x<=mi)ls=add(ls,l,mi,x,y,k);
if(y>mi)rs=add(rs,mi+1,r,x,y,k);
return u;
}
int merge(int ua,int ub,int l,int r)
{
if(!ua||!ub){if(!ua)swap(ua,ub);rec[++tpr]=ub;return ua;}
if(!Ls(ua)&&!Rs(ua))swap(ua,ub);
if(!Ls(ub)&&!Rs(ub))
{
pu(tr[ua],tr[ua],getnd(tr[ub].b,0,0,0));
pu(tr[ua],tr[ua],getnd(1,0,0,tr[ub].d));
rec[++tpr]=ub;
return ua;
}
pd(ua),pd(ub);
Ls(ua)=merge(Ls(ua),Ls(ub),l,mi);
Rs(ua)=merge(Rs(ua),Rs(ub),mi+1,r);
rec[++tpr]=ub;
return ua;
}
void recy(int u){if(ls)recy(ls);rec[++tpr]=u;if(rs)recy(rs);}
UI ask(int u,int l,int r)
{
if(l==r)return tr[u].d;
pd(u);UI res=ask(ls,l,mi);
res=mo(res+ask(rs,mi+1,r));
return res;
}
void dfs(int u,int fa,UI qx)
{
rt[u]=add(rt[u],1,w,1,w,getnd(0,1,0,0));
view(u,k)if(v[k]!=fa)
{
dfs(v[k],u,qx);
rt[u]=merge(rt[u],rt[v[k]],1,w);
rt[v[k]]=0;
}
rt[u]=add(rt[u],1,w,1,d[u],getnd(qx,0,0,0));
rt[u]=add(rt[u],1,w,1,w,getnd(1,0,1,0));
rt[u]=add(rt[u],1,w,1,w,getnd(1,1,0,0));
}
void getf(int sz)
{
f[0]=1;
rep(i,1,sz)dwn(j,i,1)f[j]=mo(f[j]+(LL)f[j-1]*(mod-i)%mod);
reverse(f,f+sz+1);
rep(i,1,sz)
{
int lst=0,num=1,nyx=mul(mod-i,mod-2);
rep(j,1,sz)if(i!=j)num=(LL)num*mo(i-j+mod)%mod;
num=(LL)mul(num,mod-2)*qy[i]%mod;
rep(i,0,sz-1)lst=(LL)mo(f[i]-lst+mod)*nyx%mod,b[i]=mo(b[i]+(LL)lst*num%mod);
}
rep(i,K,sz-1)ans=mo(ans+b[i]);
}
UI ff(UI x)
{
UI res=0,now=1;
rep(i,0,n)res=mo(res+now*b[i]%mod),now=now*x%mod;
return res;
}
int main()
{
memset(fir,-1,sizeof(fir));
n=read(),K=read(),w=read();
rep(i,1,n)d[i]=read();
rep(i,1,n-1){int x=read(),y=read();ade(x,y),ade(y,x);}
rep(i,1,n+1){dfs(1,0,i);qy[i]=ask(rt[1],1,w);recy(rt[1]),rt[1]=0;}
getf(n+1);
write(ans);
return 0;
}
一些感想

打开loj“统计”,按“最快”排序,可发现前面一堆暴力。

并不对劲的复健训练-bzoj5250:loj2473:p4365:[九省联考2018]秘密袭击的更多相关文章

  1. 【BZOJ5250】[九省联考2018]秘密袭击(动态规划)

    [BZOJ5250][九省联考2018]秘密袭击(动态规划) 题面 BZOJ 洛谷 给定一棵树,求其所有联通块的权值第\(k\)大的和. 题解 整个\(O(nk(n-k))\)的暴力剪剪枝就给过了.. ...

  2. [BZOJ5250][九省联考2018]秘密袭击(DP)

    5250: [2018多省省队联测]秘密袭击 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 3  Solved: 0[Submit][Status][D ...

  3. 并不对劲的复健训练-CF1187D

    题目大意 有两个长度为\(n\)的序列\(a_1,...,a_n\),\(b_1,...,b_n\)(\(a,b\leq n\leq 3\times 10^5\) ).一次操作是选取 \([l,r]\ ...

  4. 并不对劲的复健训练-bzoj5339:loj2578:p4593:[TJOI2018]教科书般的亵渎

    题目大意 题目链接 题解 先将\(a\)排序. \(k\)看上去等于怪的血量连续段的个数,但是要注意当存在\(a_i+1=a_{i+1}\)时,虽然它们之间的连续段为空,但是还要算上:而当\(a_m= ...

  5. 并不对劲的复健训练-CF1205B Shortest Cycle

    题目大意 有\(n\)(\(n\leq 10^5\))个数\(a_1,...,a_n\)(\(a\leq 10^{18}\)).有一个图用这个方法生成:若\(a_i\)按位与\(a_j\)不为0,则在 ...

  6. 并不对劲的复健训练-p5212 SubString

    题目大意 有一个串\(s\),一开始只知道它的一个前缀.有\(q\)(\(q\leq 10^4\))个操作,操作有两种:1.给一个字符串,表示\(s\)(\(s\)总长\(\leq 6\times 1 ...

  7. 并不对劲的复健训练-bzoj5249:loj2472:p4364[2018多省联考]IIIDX

    题目大意 给出\(n,k,d_1,...,d_n\)(\(n\leq 5\times 10^5,1<k\leq 10^9,d\leq 10^9,k\in R\)).有一个满足 对于每个点\(i\ ...

  8. 并不对劲的复健训练-bzoj5253:loj2479:p4384:[2018多省联考]制胡窜

    题目大意 给出一个字符串\(S\),长度为\(n\)(\(n\leq 10^5\)),\(S[l:r]\)表示\(S_l,S_{l+1}...,S_r\)这个子串.有\(m\)(\(m\leq 3\t ...

  9. 并不对劲的复健训练-bzoj5301:loj2534:p4462 [CQOI2018]异或序列

    题目大意 给出一个序列\(a_1,...,a_n\)(\(a,n\leq 10^5\)),一个数\(k\)(\(k\leq 10^5\)),\(m\)(\(m\leq10^5\))次询问,每次询问给\ ...

随机推荐

  1. MKAnnotation image offset with custom pin image

    </pre><pre> Your UIAnnotationView is always drawn at the same scale, the map's zoom leve ...

  2. java实现自定义同步组件的过程

    实现同步组件twinsLock:可以允许两个线程同时获取到锁,多出的其它线程将被阻塞. 以下是自定义的同步组件类,一般我们将自定义同步器Sync定义为同步组件TwinsLock的静态内部类. 实现同步 ...

  3. nodejs服务端实现post请求

    博客之前写过一篇php实现post请求的文章. 今天想到好久没有输出了,重新认识到输出的重要性.百般思索该写些什么?想来想去,想到了两点: 逐步熟练nodejs各种场景知识,针对mysql数据交互和f ...

  4. easyUI之Dialog(对话框窗口)

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  5. LinearLayout线性布局

    作用 : 线性布局会将容器中的组件一个一个排列起来, LinearLayout可以控制组件横向或者纵向排列, 通过android:orientation属性控制; 不换行属性 : 线性布局中的组件不会 ...

  6. an extra named object property

    Grunt supports the ability to split each task configuration into several separate configurations all ...

  7. MATLAB学习(六)绘图图形功能

    >> x=0:.1:2*pi;plot(x,sin(x),x,cos(x))                               >> plot(x,sin(x),'p ...

  8. Java日志体系(一)发展历程

    一.日志框架的分类 门面型日志框架: JCL: Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging SL ...

  9. JavaScript之参数传递方式

    前言 nodejs项目中遇到此问题了,具体啥需求暂时不说~ 本博文,关于理论部分,主要是摘抄"推荐文献"第一篇:关于实验部分是看该博文之前做的,两者无干系. [结论]对于普通函数, ...

  10. const成员变量

    #include <iostream> using namespace std; class A { public: A(int size) : SIZE(size) {}; privat ...