jzoj5987. 【WC2019模拟2019.1.4】仙人掌毒题 (树链剖分+概率期望+容斥)
题面
题解
又一道全场切的题目我连题目都没看懂……细节真多……
先考虑怎么维护仙人掌。在线可以用LCT,或者像我代码里先离线,并按时间求出一棵最小生成树(或者一个森林),然后树链剖分。如果一条边不是生成树上的边,它肯定会和树上\(u,v\)这条路径构成一个环,然后对于每条树边记录一下这条树边被覆盖过没有。如果\(u,v\)路径上有任何一条树边被覆盖过,那么就说明路径上有一条边已经在一个简单环中,这条非树边就不能加。否则就加上这条边并让这条路径上所有树边的覆盖次数加一
然后考虑期望连通块个数。首先根据我也不知道是什么的期望的线性,可以分开考虑。比方说一个森林,连通块个数等于点数\(-\)边数,那么期望连通块个数就是期望点数\(-\)期望边数。
然后考虑沙漠,沙漠的连通块个数为点数\(-\)边数\(+\)环数。可以这么考虑,如果没有环,那么就是点数\(-\)边数,而对于一条加进去会成环的边,它被多减了一次,那么就要加上去,而多减的边数就是环数
于是只要分别考虑期望点数,期望边数,期望环数即可。顺便黑白也可以分开考虑,即如果\(w=0\)的话只需要考虑白点就可以了
设\(0\)点为白点,\(1\)点为黑点,那么对于一个点,它在染完色之后仍为白色的概率为\((\frac{n-1}{n})^t\),那么白点的期望个数就是\(n\times (\frac{n-1}{n})^t\),为黑点的概率就是\(1\)减去为白点的概率,黑点期望个数同理
然后考虑边为白色的概率,就是\((\frac{n-2}{n})^t\),边为黑色的概率的话,根据容斥原理,为\(1-2(\frac{n-1}{n})^t+(\frac{n-2}{n})^t\)
然后是环,设环上点数为\(p\),那么环为白色的概率为\((\frac{n-p}{n})^t\)。然而环为黑色的概率怎么算?记\(f_i\)为\(i\)个点全黑的概率,\(g_i\)为\(i\)个点全白的概率,那么有转移\(f_i=1-\sum_{j=0}^{i-1}f_jg_{i-j}{i\choose j}\),就是枚举有多少个黑点并容斥,可以用多项式求逆解决
然而多项式求逆太烦了……我们可以用容斥原理计算\(f_p\),有$$f_p=\sum_{j=0}p(-1)j{p\choose j}(\frac{n-j}{n})^t$$
因为\(\sum p=O(n)\),所以这里的复杂度是没有问题的(\(\sum p=O(n)\)的话,是因为生成树上每条边最多在一个环中,每个环的点数等于边数,所以环上总点数\(=\)生成树上边数\(+\)成环的边数,成环边数不会大于\(O(n)\),所以有\(\sum p=O(n)\))
总的时间复杂度为\(O(n\log t+m\log^2n)\)
因为码量有点大,所以代码分块了……这是我这几天来唯一没有压行的代码了……
//minamoto
#include<bits/stdc++.h>
#define R register
#define ls (p<<1)
#define rs (p<<1|1)
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5,M=2.5e5+5,P=998244353;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
return res;
}
int n,m,t,w;
struct seg{
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int dfn[N],top[N],sz[N],fa[N],dep[N],son[N],cnt;
void dfs1(int u){
sz[u]=1,dep[u]=dep[fa[u]]+1;
go(u)if(v!=fa[u]){
fa[v]=u,dfs1(v),sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t,dfn[u]=++cnt;if(!son[u])return;
dfs2(son[u],t);
go(u)if(v!=fa[u]&&v!=son[u])dfs2(v,v);
}
bool tag[N<<2],vis[N<<2];
void pd(int p){
if(tag[p]){
tag[ls]=tag[rs]=1;
vis[ls]=vis[rs]=1;
tag[p]=0;
}
}
void update(int p,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)return (void)(tag[p]=vis[p]=1);
int mid=(l+r)>>1;pd(p);
if(ql<=mid)update(ls,l,mid,ql,qr);
if(qr>mid)update(rs,mid+1,r,ql,qr);
vis[p]=vis[ls]|vis[rs];
}
bool query(int p,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)return vis[p];
int mid=(l+r)>>1;pd(p);
if(ql<=mid&&query(ls,l,mid,ql,qr))return true;
if(qr>mid&&query(rs,mid+1,r,ql,qr))return true;
return false;
}
void change_path(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
update(1,1,n,dfn[top[u]],dfn[u]),u=fa[top[u]];
}if(dep[u]<dep[v])swap(u,v);
if(u!=v)update(1,1,n,dfn[son[v]],dfn[u]);
}
bool query_path(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
if(query(1,1,n,dfn[top[u]],dfn[u]))return false;
u=fa[top[u]];
}if(dep[u]<dep[v])swap(u,v);
if(u!=v&&query(1,1,n,dfn[son[v]],dfn[u]))return false;
return true;
}
int LCA(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=fa[top[u]];
}return dep[u]<dep[v]?u:v;
}
int dis(int u,int v){return dep[u]+dep[v]-(dep[LCA(u,v)]<<1)+1;}
void init(){
fp(i,1,n)if(!dfn[i])dfs1(i),dfs2(i,i);
}
}T;
struct QAQ{
struct eg{int u,v,is;}e[M];
int fa[N],inv[N],fac[N];
int ndwh,ndbl,edwh,edbl,ciwh,cibl,invn,res,u,v,p,gg,invp;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline int C(R int n,R int m){return m>n?0:1ll*fac[n]*inv[m]%P*inv[n-m]%P;}
int merge(int u,int v){
u=find(u),v=find(v);
if(u==v)return false;
return fa[u]=v,true;
}
void init(){
invn=ksm(n,P-2);
ndwh=ksm(mul(n-1,invn),t);
ndbl=dec(1,ndwh);
edwh=ksm(mul(n-2,invn),t);
edbl=add(1,dec(edwh,mul(2,ndwh)));
res=(w==1)?n:mul(ndwh,n);
fac[0]=inv[0]=1;fp(i,1,n)fac[i]=mul(fac[i-1],i);
inv[n]=ksm(fac[n],P-2);fd(i,n-1,1)inv[i]=mul(inv[i+1],i+1);
}
void MAIN(){
n=read(),m=read(),t=read(),w=read();
init();
fp(i,1,n)fa[i]=i;
fp(i,1,m){
e[i].u=read(),e[i].v=read();
if(merge(e[i].u,e[i].v)){
e[i].is=1,T.add(e[i].u,e[i].v),T.add(e[i].v,e[i].u);
}
}
T.init();
fp(i,1,m){
if(e[i].u!=e[i].v){
u=e[i].u,v=e[i].v;
if(!e[i].is){
if(T.query_path(u,v)){
T.change_path(u,v);
res=dec(res,edwh);
if(w==1)res=dec(res,edbl);
p=T.dis(u,v),invp=ksm(p,P-2);
res=add(res,ksm(mul(n-p,invn),t));
if(w==1){
gg=0;
for(R int j=0,ty=1;j<=p;++j,ty=P-ty)
gg=add(gg,1ll*ty*C(p,j)%P*ksm(mul(n-j,invn),t)%P);
res=add(res,gg);
}
}
}else{
res=dec(res,edwh);
if(w==1)res=dec(res,edbl);
}
}print(res);
}
}
}loli;
int main(){
// freopen("testdata.in","r",stdin);
// freopen("testdata.out","w",stdout);
freopen("cactus.in","r",stdin);
freopen("cactus.out","w",stdout);
loli.MAIN();
return Ot(),0;
}
jzoj5987. 【WC2019模拟2019.1.4】仙人掌毒题 (树链剖分+概率期望+容斥)的更多相关文章
- JZOJ 5987 仙人掌毒题 (树链剖分 + 容斥)
跟仙人掌其实没啥关系- Here 注意 每一次都O(n)O(n)O(n)一下算某些点都是黑点的概率其实并不是O(n2)O(n^2)O(n2),因为每个环只用算一次. #include <ccty ...
- jzoj5986. 【WC2019模拟2019.1.4】立体几何题 (权值线段树)
传送门 题面 题解 不难看出每个点的大小为行列限制中较小的那一个(因为数据保证有解) 对于行的每个限制,能取到的个数是列里限制大于等于它的数的个数,同理,对于列是行里大于它的个数(这里没有等于,为了避 ...
- 2019 icpc南昌全国邀请赛-网络选拔赛J题 树链剖分+离线询问
链接:https://nanti.jisuanke.com/t/38229 题意: 给一棵树,多次查询,每次查询两点之间权值<=k的边个数 题解: 离线询问,树链剖分后bit维护有贡献的位置即可 ...
- 2019 ACM-ICPC 西安全国邀请赛 E-Tree 树链剖分+线段树
题意 给一颗带点权的树,三种操作 \(1~s~t\) 修改从1到s的路径上的所有点,\(a[i]=a[i]|t\) \(2~s~t\) 修改从1到s的路径上的所有点,\(a[i]=a[i]\& ...
- BZOJ2040[2009国家集训队]拯救Protoss的故乡——模拟费用流+线段树+树链剖分
题目描述 在星历2012年,星灵英雄Zeratul预测到他所在的Aiur行星在M天后会发生持续性暴雨灾害,尤其是他们的首都.而Zeratul作为星灵族的英雄,当然是要尽自己最大的努力帮助星灵族渡过这场 ...
- [BZOJ2164]采矿【模拟+树链剖分+线段树】
Online Judge:Bzoj2164 Label:模拟,树链剖分,线段树 题目描述 浩浩荡荡的cg大军发现了一座矿产资源极其丰富的城市,他们打算在这座城市实施新的采矿战略.这个城市可以看成一棵有 ...
- [JZOJ5987] 仙人掌毒题
Description Solution 套路题... 全他娘的是套路... 首先如何处理仙人掌,可以在线拿 \(lct\) 维护,或者离线之后树剖.(\(lct\) 维护太毒了写不来,就离线树剖了又 ...
- jzoj5988. 【WC2019模拟2019.1.4】珂学计树题 (burnside引理)
传送门 题面 liu_runda曾经是个喜欢切数数题的OIer,往往看到数数题他就开始刚数数题.于是liu_runda出了一个数树题.听说OI圈子珂学盛行,他就在题目名字里加了珂学二字.一开始liu_ ...
- 6359. 【NOIP2019模拟2019.9.15】小ω的树(tree)(定期重构)
题目描述 题解 qy的毒瘤题 CSP搞这种码农题当场手撕出题人 先按照边权从大到小建重构树,然后40%暴力修改+查找即可 100%可以定期重构+平衡规划,每次把B个询问拉出来建虚树,在虚树上暴力维护每 ...
随机推荐
- easyui Combotree 怎么加载数据 支持多选
1.开发环境vs2012 mvc4 c# 2.HTML前端代码 <%@ Page Language="C#" AutoEventWireup="true" ...
- 九度OJ 1112:拦截导弹 (DP、最长下降子序列)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:3124 解决:1525 题目描述: 某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能 ...
- 支付宝cookie 是支付密码 不是登录密码
开发文档/ 手机网站支付 / 产品介绍 开放平台文档中心 https://docs.open.alipay.com/203/105288
- Node 文件上传,ZIP
上传文件: 很多人会使用第三包进行文件的上传,例如formidable. 我也研究过,可是与Express3.x框架一起使用时,发现上传的文件总是找不到.结果原因是下面这句导致: app.use(ex ...
- spring和springmvc中,Configuration注解Bean重复加载
问题:bean重复加载1.如下代码所示,开启Configuration注解,实现Bean代码注入,发现bean重复加载 @Configuration public class EhCacheConfi ...
- signal( SIGINT, SigIntHandler )
signal 的第1个参数signum表示要捕捉的信号,第2个参数是个函数指针,表示要对该信号进行捕捉的函数,该参数也可以是SIG_DEF(表示交由系统缺省处理,相当于白注册了)或SIG_IGN(表示 ...
- UVA10518 How Many Calls? —— 矩阵快速幂
题目链接:https://vjudge.net/problem/UVA-10518 题解: 问:求斐波那契数f[n]的时候调用了多少次f[n] = f[n-1] + f[n-2],没有记忆化,一直递归 ...
- 记录下linux好用的命令
http://mp.weixin.qq.com/s/LU1iAWfssv1x-QMX6hJqmQ
- ansible 魔法变量
hostvars 可以让你调用其他host的变量和facts, 即使你没有在这个机器上执行过playbook, 你仍然可以访问变量, 但是不能访问facts. 例如: {{ hostvars['te ...
- 让tomcat启动时,自动加载你的项目
在tomcat-->conf-->serve.xml文件最后加上 <Context path="/atest" docBase="E:\Workspac ...