题目:https://loj.ac/problem/2473

   https://www.luogu.org/problemnew/show/P4365

参考:https://blog.csdn.net/xyz32768/article/details/82952313

   https://zhang-rq.github.io/2018/05/04/%E4%B9%9D%E7%9C%81%E8%81%94%E8%80%832018-%E7%A7%98%E5%AF%86%E8%A2%AD%E5%87%BBCoaT/

   https://blog.csdn.net/qq_35649707/article/details/79923740

关于如何已知 n+1 个点值 n2 还原出 n 次多项式的系数:

   https://zhang-rq.github.io/2018/05/04/%E6%8B%89%E6%A0%BC%E6%9C%97%E6%97%A5%E6%8F%92%E5%80%BC%E6%B3%95%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/?tdsourcetag=s_pctim_aiomsg 

看到连值域也只有 1666 ,首先想到的是枚举第 k 大值是什么,设为 w 。

然后自己只能想到 n6 的 DP ……就是记录 “有 i 个 > w 的值和 j 个 = w 的值” 的连通块个数,求出第 k 大值恰好是 w 的连通块个数。

其实可以这样考虑,就是求 “第 k 大值 >= w ” 的连通块的个数。设为 f[ w ] 的话,答案就是 \( \sum\limits_{w=1}^{W}f[w] \) 。这样对于一个 w 就会被算 w 遍,恰好是答案。

然后就可以枚举 w ,令 \( dp[i][j] \) 表示以 i 为根的子树、有 j 个点的值 >=w 的连通块个数。 j 是和子树大小有关的,所以 DP 是 n3

正解是这样考虑:

用整体 DP 的思想,考虑一次 DP 把所有 w 的答案都做出来。

那么 DP 的时候每个点就记录了 n2 个值,来表示有 j 个点的值 >= w 的连通块个数。形如:

转移的时候就是当前点 cr 与孩子 v 的横着的格子对应转移;对于一个横着的格子伸出去的竖着的数组,转移形如卷积的样子。

所以考虑把每个竖着的数组写成一个多项式的样子。\( dp[cr][w]=\sum\limits_{i=0}^{\infty}a_i * x^i \) 这样。

如果把多个 w 像这样同时 DP ,可以发现一个点自己对数组的影响就是:

  1.在 w<a[cr] 的那些位置的多项式上 +1,表示多出一个 “有0个点>=w” 的连通块;

  2.在 w>=a[cr] 的那些位置的多项式上 *x ,表示原来 “有 j 个点 >=w ” 的连通块会变成 “有 j+1 个点 >=w ” 的连通块。

因为一个点对整个横着的数组的操作很少,所以考虑对横着的数组用动态开点线段树维护。

  比如可能经过了好几个点,对 w=3 这个位置和 w=4 这个位置的操作全都是 *x ,那么 w=3 和 w=4 的这两个位置就不用分别维护,像粘在一起的一样打标记就行了。

  所以这样可以通过把询问一起做来降低复杂度。

转移就是线段树合并。这样复杂度是 nlogn 。

但是线段树一个节点上维护了一个多项式。要合并很麻烦。所以考虑把 x 换成实际的值,这样线段树的节点上就只记录了一个值,合并的时候就是 O(1) 了。

把 x 换成实际的值求出来的结果是多项式的点值。所以做 n+1 遍求出 n+1 个点值,就能用拉格朗日插值 O(n2) 还原出系数了。

已知原来要求的多项式是 \( \sum\limits_{i=0}^{\infty}a_i * x^i \) ,答案是每个点的线段树所有叶子的多项式中 次数>=k 的那些项的系数和。“所有叶子”表示考虑所有 w 的情况。

那个“每个点”很不好。所以考虑再记一个多项式表示“子树里所有点”的情况,即 \( \sum\limits_{i=0}^{\infty}(\sum\limits_{j \in tree_i}a_{j,i} ) * x^i \) 。

线段树转移的种种就参见参考的那些博客……

注意 unsigned int 类型的所有数都是 >=0 的,也就是它的负数也是 >=0 的。所以 upt( ) 不能写 if(x<0) ... 这样。

自己写(抄)的不知为何常数很大,在洛谷上只能60分,在 LOJ 上可以垫底 AC 。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define u32 unsigned int
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=,M=N*N<<; u32 mod=;
u32 upt(u32 x){while(x>=mod)x-=mod;return x;}
u32 pw(int x,int k)
{u32 ret=;while(k){if(k&)ret=ret*x%mod;x=x*x%mod;k>>=;}return ret;} int n,m,k,a[N],hd[N],xnt,to[N<<],nxt[N<<];
int rt[N],tot,ls[M],rs[M],dpl[M],dtop;
struct Node{
u32 a,b,c,d;
Node(u32 a=,u32 b=,u32 c=,u32 d=):a(a),b(b),c(c),d(d) {}
Node operator* (const Node &t)const
{
return Node(a*t.a%mod,upt(b*t.a%mod+t.b),
upt(a*t.c%mod+c),upt(b*t.c%mod+t.d+d));
}
void init(){a=;b=c=d=;}
}vl[M];
int nwnd()
{
if(!dtop)return ++tot;
int ret=dpl[dtop--]; vl[ret].init(); return ret;
}
void del(int &x)
{
if(ls[x])del(ls[x]); if(rs[x])del(rs[x]);
dpl[++dtop]=x; x=;
}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void pshd(int cr)
{
if(!ls[cr])ls[cr]=nwnd(); if(!rs[cr])rs[cr]=nwnd();
vl[ls[cr]]=vl[ls[cr]]*vl[cr];
vl[rs[cr]]=vl[rs[cr]]*vl[cr]; vl[cr].init();
}
void mdfy(int l,int r,int &cr,int L,int R,Node k)
{
if(L>R)return; if(!cr)cr=nwnd();
if(l>=L&&r<=R){vl[cr]=vl[cr]*k;return;}
int mid=l+r>>; pshd(cr);
if(L<=mid)mdfy(l,mid,ls[cr],L,R,k);
if(mid<R)mdfy(mid+,r,rs[cr],L,R,k);
}
u32 qry(int l,int r,int cr)
{
if(l==r)return vl[cr].d;
int mid=l+r>>; pshd(cr);
return upt(qry(l,mid,ls[cr])+qry(mid+,r,rs[cr]));
}
void mrg(int &x,int &y)
{
if(!x)swap(x,y);if(!y)return;//
if(!ls[x]&&!rs[x])swap(x,y);
if(!ls[y]&&!rs[y])
{
vl[x]=vl[x]*Node(vl[y].b,,,vl[y].d);
return;
}
pshd(x); pshd(y);/////
mrg(ls[x],ls[y]); mrg(rs[x],rs[y]);
}
void dfs(int cr,int fa,int x)
{
mdfy(,m,rt[cr],,m,Node(,,,));//f=1//m not n!
//but g isn't changed so del()
for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=fa)
{
dfs(v,cr,x);
mrg(rt[cr],rt[v]);
del(rt[v]);
}
mdfy(,m,rt[cr],,a[cr],Node(x,,,));
mdfy(,m,rt[cr],,m,Node(,,,)*Node(,,,));
}
int c[N],f[N],g[N],inv[N],ans[N];
void solve()
{
for(int x=;x<=n+;x++)
{
dfs(,,x);
c[x]=qry(,m,rt[]);//m not n!!
del(rt[]);///when dfs del(rt[v])//time?n^2
}
f[]=mod-; f[]=;
for(int i=;i<=n+;i++)
{
for(int j=n+;j;j--)
f[j]=upt((mod-i)*f[j]%mod+f[j-]);
f[]=(mod-i)*f[]%mod;
}
inv[]=;
for(int i=;i<=n+;i++)
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
u32 ans=;
for(int i=;i<=n+;i++)
{
g[]=(mod-f[])*inv[i]%mod;
for(int j=;j<=n;j++)
g[j]=upt(g[j-]-f[j]+mod)*inv[i]%mod;
u32 pl=;
for(int j=k;j<=n;j++)pl=upt(pl+g[j]);
u32 ml=c[i];
for(int j=;j<=n+;j++)
if(j<i) ml=ml*inv[i-j]%mod;
else if(j>i) ml=ml*(mod-inv[j-i])%mod;
ans=upt(ans+ml*pl%mod);
}
printf("%d\n",ans);
}
int main()
{
n=rdn();k=rdn();m=rdn();
for(int i=;i<=n;i++)a[i]=rdn();
for(int i=,u,v;i<n;i++)
u=rdn(),v=rdn(),add(u,v),add(v,u);
solve(); return ;
}

LOJ 2743(洛谷 4365) 「九省联考 2018」秘密袭击——整体DP+插值思想的更多相关文章

  1. LOJ #2473. 「九省联考 2018」秘密袭击

    #2473. 「九省联考 2018」秘密袭击 链接 分析: 首先枚举一个权值W,计算这个多少个连通块中,第k大的数是这个权值. $f[i][j]$表示到第i个节点,有j个大于W数的连通块的个数.然后背 ...

  2. Loj #2479. 「九省联考 2018」制胡窜

    Loj #2479. 「九省联考 2018」制胡窜 题目描述 对于一个字符串 \(S\),我们定义 \(|S|\) 表示 \(S\) 的长度. 接着,我们定义 \(S_i\) 表示 \(S\) 中第 ...

  3. 「九省联考 2018」IIIDX 解题报告

    「九省联考 2018」IIIDX 这什么鬼题,送的55分要拿稳,实测有60? 考虑把数值从大到小摆好,每个位置\(i\)维护一个\(f_i\),表示\(i\)左边比它大的(包括自己)还有几个数可以选 ...

  4. 【LOJ】#2479. 「九省联考 2018」制胡窜

    题解 老了,国赛之前敲一个后缀树上LCT和线段树都休闲的很 现在后缀树上线段树合并差点把我写死 主要思路就是后缀树+线段树合并+容斥,我相信熟练的OIer看到这已经会了 但就是不想写 但是由于我过于老 ...

  5. LOJ#2471「九省联考 2018」一双木棋 MinMax博弈+记搜

    题面 戳这里 题解 因为每行取的数的个数是单调不增的,感觉状态数不会很多? 怒而记搜,结果过了... #include<bits/stdc++.h> #define For(i,x,y) ...

  6. [loj 2478][luogu P4843]「九省联考 2018」林克卡特树

    传送门 Description 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一 ...

  7. @loj - 2478@「九省联考 2018」林克卡特树

    目录 @description@ @solution@ @part - 1@ @part - 2@ @accepted code@ @details@ @description@ 小 L 最近沉迷于塞 ...

  8. loj2472 「九省联考 2018」IIIDX

    ref #include <algorithm> #include <iostream> #include <cstdio> using namespace std ...

  9. 洛谷 P4363 [九省联考2018]一双木棋chess 解题报告

    P4363 [九省联考2018]一双木棋chess 题目描述 菲菲和牛牛在一块\(n\)行\(m\)列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落 ...

随机推荐

  1. Kaggle(2):验证和过分拟合

    目前看来,随机森林是比较常用且有效的分类算法.以下先简要介绍python中随机森林的使用方法,然后谈谈分类结果的准确度验证和过拟合等两个重要问题. 1.随机森林的参数 在Scikit learn中使用 ...

  2. this是什么!

    this 1.js的关键字指定一个对象,然后去替代他 函数内的this    函数外的this 函数内的this指向行为发生的主体 函数外的this都指向window 2.函数内的this和函数在什么 ...

  3. HDU 4463 Outlets(最小生成树给坐标)

    Problem Description In China, foreign brand commodities are often much more expensive than abroad. T ...

  4. react native 之 Android物理返回键

    基本用法 根据文档,安卓back键的处理主要就是一个事件监听: BackAndroid.addEventListener('hardwareBackPress', this.onBackPressed ...

  5. [LeetCode&Python] Problem 717. 1-bit and 2-bit Characters

    We have two special characters. The first character can be represented by one bit 0. The second char ...

  6. OpenCV 自定义任意区域形状及计算平均值 方差

    opencv中有矩形的Rect函数.圆形的circl函数等,那么任意形状怎么取呢?方法1:点乘,将其形状与图像进行点乘,求其形状对应的图像形状:方法2:用findContours函数得对应的形状区域, ...

  7. 20155219&20155224 《信息安全系统设计基础》实验二 固件程序设计

    实验二 固件程序设计-1-MDK 0. 注意不经老师允许不准烧写自己修改的代码 1. 两人(个别三人)一组 2. 参考云班课资源中"信息安全系统实验箱指导书.pdf "第一章,1. ...

  8. 获取div,表单中的内容

    获得内容 - text().html() 以及 val() 三个简单实用的用于 DOM 操作的 jQuery 方法: text() - 设置或返回所选元素的文本内容 html() - 设置或返回所选元 ...

  9. ccf 201312-04 有趣的数(组合数学)

    问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高 ...

  10. npm常规命令行集合

    最近在摸索vue-cli脚手架的安装,中间用到了一些node的npm命令行,进行了一些整理,并且这个会一直搜集整理更新! 1,常规文件操作命令 cd..                   返回当前文 ...