LOJ 2743(洛谷 4365) 「九省联考 2018」秘密袭击——整体DP+插值思想
题目:https://loj.ac/problem/2473
https://www.luogu.org/problemnew/show/P4365
参考:https://blog.csdn.net/xyz32768/article/details/82952313
https://blog.csdn.net/qq_35649707/article/details/79923740
关于如何已知 n+1 个点值 n2 还原出 n 次多项式的系数:
看到连值域也只有 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+插值思想的更多相关文章
- LOJ #2473. 「九省联考 2018」秘密袭击
#2473. 「九省联考 2018」秘密袭击 链接 分析: 首先枚举一个权值W,计算这个多少个连通块中,第k大的数是这个权值. $f[i][j]$表示到第i个节点,有j个大于W数的连通块的个数.然后背 ...
- Loj #2479. 「九省联考 2018」制胡窜
Loj #2479. 「九省联考 2018」制胡窜 题目描述 对于一个字符串 \(S\),我们定义 \(|S|\) 表示 \(S\) 的长度. 接着,我们定义 \(S_i\) 表示 \(S\) 中第 ...
- 「九省联考 2018」IIIDX 解题报告
「九省联考 2018」IIIDX 这什么鬼题,送的55分要拿稳,实测有60? 考虑把数值从大到小摆好,每个位置\(i\)维护一个\(f_i\),表示\(i\)左边比它大的(包括自己)还有几个数可以选 ...
- 【LOJ】#2479. 「九省联考 2018」制胡窜
题解 老了,国赛之前敲一个后缀树上LCT和线段树都休闲的很 现在后缀树上线段树合并差点把我写死 主要思路就是后缀树+线段树合并+容斥,我相信熟练的OIer看到这已经会了 但就是不想写 但是由于我过于老 ...
- LOJ#2471「九省联考 2018」一双木棋 MinMax博弈+记搜
题面 戳这里 题解 因为每行取的数的个数是单调不增的,感觉状态数不会很多? 怒而记搜,结果过了... #include<bits/stdc++.h> #define For(i,x,y) ...
- [loj 2478][luogu P4843]「九省联考 2018」林克卡特树
传送门 Description 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一 ...
- @loj - 2478@「九省联考 2018」林克卡特树
目录 @description@ @solution@ @part - 1@ @part - 2@ @accepted code@ @details@ @description@ 小 L 最近沉迷于塞 ...
- loj2472 「九省联考 2018」IIIDX
ref #include <algorithm> #include <iostream> #include <cstdio> using namespace std ...
- 洛谷 P4363 [九省联考2018]一双木棋chess 解题报告
P4363 [九省联考2018]一双木棋chess 题目描述 菲菲和牛牛在一块\(n\)行\(m\)列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落 ...
随机推荐
- Python写一个批量生成账号的函数
批量生成账户信息,产生的账户由@sina.com结尾,长度由用户输入,产生多少条也由用户输入,用户名不能重复,用户名必须由大写字母.小写字母和数字组成. def Users(num,len): # n ...
- python day09作业
- Python 特殊关系
class Foo: def __init__(self): # 初始化操作 print("我是init, 我是老二") print("初始化操作. 在创建对象的时候自动 ...
- Python基础2--Python简单数据类型
python简单数据类型 1 list list的创建,使用[] a_list = [‘a’, ’b’, ‘c’] print a_list print a_list[0] #a 如果去list的最后 ...
- foreman ubuntu16快速安装
Quickstart Guide The Foreman installer is a collection of Puppet modules that installs everything re ...
- wx小程序获取用户位置信息
wx小程序内置的接口只能获取用户的坐标,通过微信位置服务获取用户地址: http://lbs.qq.com/qqmap_wx_jssdk/index.html 注:需要在key的设置中打开webSer ...
- 4.App测试与Web测试的不同
注释:*蓝色为不同点,红色为测试类型* 测试工具不同 Web自动化用Selenium APP自动化用Appium 软件架构不同 App为C/S架构 Web为B/S架构 需要进行安装卸载更新测试 第一次 ...
- SQL注入之Sqli-labs系列第十四关(基于双引号POST报错注入)
开始挑战第十四关(Double Injection- Double quotes- String) 访问地址,输入报错语句 ' '' ') ") - 等使其报错 分析报错信息 很明显是 ...
- phpcms 操作数据库 增删改查
数据库的其他类继承的都是libs/class/model.class.php 这里面有写好的操作数据库的常用方法 1.增 insert($data, $return_insert_id = false ...
- 【转载】 【caffe转向pytorch】caffe的BN层+scale层=pytorch的BN层
原文地址: https://blog.csdn.net/u011668104/article/details/81532592 ------------------------------------ ...