[loj 6496]「雅礼集训 2018 Day1」仙人掌
传送门
Description
给出一张 \(n\)个点 \(m\)条边的无向连通图,其中每条边至多属于一个简单环,保证没有自环,可能有重边。你需要为其中每条边定向,其中第 \(i\)个点的出度不能超过\(a_i\) ,求方案数(对\(998244353\)取模)。
Solution
建出原图的圆方树,其中两个点和一条边组成的不算做一个双联通分量,圆方树的的根是\(1\)
定义\(f[x][i]\)表示,第\(x\)个点,它上面的点给它的入度为\(i\),以\(x\)为根的子树内给边定向的方案数。
更清楚一点:
如果\(x\)是一个圆点,且它的父亲也是圆点
\(f[x][0/1]\)即表示它的父亲节点与它之间的边是否是指向\(x\)的
如果\(x\)是一个方点,且它的父亲是圆点
\(f[x][0/1/2]\)即表示这个环的最上面的两条边(就是于\(fa\)直接相连的那两条),不指向\(fa\)的数量(\(0/1/2\))
如果\(x\)是一个圆点,且它的父亲是方点
\(f[x][0/1/2]\)表示的就是它所在的环上与它直接相邻的两条边,指向它自己的边的数量\((0/1/2)\)
\(dfs\)时考虑分情况转移:
\(x\)是圆点,显然有:
\[f[x][0]=\sum_{k_1+K_2+...+k_p\leq a[x]}\prod_{v_i} f[v_i][Sum_{v_i}-k_i]
\]其中,如果\(v_i\)是方点,\(Sum_{v_i}=2\),如果\(v_i\)是圆点,\(Sum_{v_i}=1\)
因为是一个背包的形式,可以直接利用\(NTT\)加速
\(x\)是方点,设\(x\)的父亲节点是\(y\)
枚举环上与\(y\)相连的一条边的方向,然后顺着环递推即可
最后,在进行分治\(NTT\)时,每次都把两个数组全部清空复杂度是不对的
每次做完后,把当前的数组有修改的地方清为\(0\)就行
代码写得真的很清楚啦
Code
#include<bits/stdc++.h>
#define min(a,b) ((a)<(b)?(a):(b))
namespace IO
{
const int lim=(1<<20)+5;
char buf[lim+5],*S,*T;
inline char gc(){if(S==T){T=(S=buf)+fread(buf,1,lim,stdin);if(S==T)return EOF;}return *S++;}
inline int read()
{
int x;char ch;bool f;
for(f=0;(ch=gc())<'0'||ch>'9';f=ch=='-');
for(x=ch^'0';(ch=gc())>='0'&&ch<='9';x=(x<<1)+(x<<3)+(ch^'0'));
return f?-x:x;
}
}
#define reg register
#define son e[i].to
const int MN=1e5+5,P=998244353,g=3,invg=332748118,MX=524288;
int u[MX],v[MX],N;
void Add(int &x,int y){x+=y;if(x>=P)x-=P;}
class MyNTT
{
int pos[MX],invN,di;
int fpow(int x,int m){int r=1;for(;m;m>>=1,x=1ll*x*x%P)if(m&1)r=1ll*r*x%P;return r;}
void NTT(int *a,bool type)
{
reg int w,wn,i,j,p,k,X,Y;
for(i=0;i<N;++i) if(i<pos[i]) std::swap(a[pos[i]],a[i]);
for(i=1;i<N;i<<=1)
{
wn=fpow(type?g:invg,(P-1)/(i<<1));
for(p=i<<1,j=0;j<N;j+=p)
for(w=1,k=0;k<i;++k,w=1ll*w*wn%P)
{
X=a[j+k];Y=1ll*a[i+j+k]*w%P;
a[j+k]=(X+Y)%P;a[i+j+k]=(X-Y+P)%P;
}
}
if(!type)for(i=0;i<N;++i)a[i]=1ll*invN*a[i]%P;
}
public:
void Pro(int *a,int *b,int n,int m)
{
for(di=0,N=1;N<n+m;N<<=1,++di);invN=fpow(N,P-2);
reg int i;
for(i=0;i<N;++i)pos[i]=(pos[i>>1]>>1)|((i&1)<<(di-1));
NTT(a,1);NTT(b,1);
for(i=0;i<N;++i)a[i]=1ll*a[i]*b[i]%P;
NTT(a,0);
}
}ntt;
int pin,t;
struct Node{int x,nex;}O[MN*40];
class MyCDQ
{
int res[MN];
public:
struct poly
{
int hr,n;
poly(int _=0,int __=-1):hr(_),n(__){}
void push_back(int x){++n;O[++pin]=(Node){x,hr};hr=pin;}
void To_array(int *a){for(int i=hr,j=n;i;i=O[i].nex)a[j--]=O[i].x;}
}p[MN];
poly Cdq(int l,int r)
{
if(l==r) return p[l];
reg int mid=(l+r)>>1;
poly L=Cdq(l,mid),R=Cdq(mid+1,r);
L.To_array(u);R.To_array(v);
ntt.Pro(u,v,L.n+1,R.n+1);
poly ans;for(reg int i=0;i<L.n+R.n+1;++i)ans.push_back(u[i]);
for(reg int i=0;i<N;++i) u[i]=0;
for(reg int i=0;i<N;++i) v[i]=0;
return ans;
}
void clear(){t=0;}
void add(){++t;p[t].hr=0;p[t].n=-1;}
void pb(int x){p[t].push_back(x);}
void get_ans(int &_0,int &_1,int &_2,int limi)
{
poly c=Cdq(1,t);
c.To_array(res);
for(reg int i=c.n+1;i<=limi;++i) res[i]=0;
for(reg int i=1;i<=limi;++i) Add(res[i],res[i-1]);
_0=res[limi];if(limi)_1=res[limi-1];if(limi>1)_2=res[limi-2];
}
}cdq;
int n,m,du[MN],hr[MN],Hr[MN<<1],en=1,A[MN],f[MN<<1][3];
struct edge{int to,nex;}e[MN<<3];
inline void ins(int x,int y,int *h){e[++en]=(edge){y,h[x]};h[x]=en;}
int dfn[MN],low[MN],st[MN],tp,ind,num;
void tj(int x,int F=0)
{
dfn[x]=low[x]=++ind;st[tp++]=x;
reg int i;
for(i=hr[x];i;i=e[i].nex)if(i^F^1)
{
if(!dfn[son])
{
tj(son,i);
low[x]=min(low[x],low[son]);
if(dfn[x]==low[son])
{
++num;ins(x,num,Hr);
for(;st[tp]!=son;--tp) ins(num,st[tp-1],Hr);
}
else if(low[son]>dfn[x]) --tp,ins(x,son,Hr);
}
else low[x]=min(low[x],dfn[son]);
}
}
void dfs(int x)
{
reg int i,j,_;
for(i=Hr[x];i;i=e[i].nex) dfs(son);
if(x<=n)
{
if(!Hr[x]) f[x][0]=1,f[x][1]=A[x]>0,f[x][2]=A[x]>1;
else
{
cdq.clear();
for(i=Hr[x];i;i=e[i].nex)
{
cdq.add();
if(son>n) cdq.pb(f[son][2]);
cdq.pb(f[son][1]);cdq.pb(f[son][0]);
}
cdq.get_ans(f[x][0],f[x][1],f[x][2],A[x]);
}
}
else
{
for(_=0;_<2;++_)
{
int S0[2]={0,0},S1[2];S0[_]=1;
for(i=Hr[x];i;i=e[i].nex)
{
S1[0]=(1ll*S0[0]*f[son][1]+1ll*S0[1]*f[son][2])%P;
S1[1]=(1ll*S0[0]*f[son][0]+1ll*S0[1]*f[son][1])%P;
S0[0]=S1[0];S0[1]=S1[1];
}
Add(f[x][_+1],S0[0]);
Add(f[x][_],S0[1]);
}
}
}
int main()
{
num=n=IO::read();m=IO::read();
reg int i,x,y;
for(i=1;i<=m;++i) x=IO::read(),y=IO::read(),ins(x,y,hr),ins(y,x,hr),++du[x],++du[y];
for(i=1;i<=n;++i) A[i]=IO::read(),A[i]=min(A[i],du[i]);
for(i=1;i<=n;++i) if(!dfn[i]) tj(i);dfs(1);
return 0*printf("%d\n",f[1][0]);
}
Blog来自PaperCloud,未经允许,请勿转载,TKS!
[loj 6496]「雅礼集训 2018 Day1」仙人掌的更多相关文章
- [LOJ 6031]「雅礼集训 2017 Day1」字符串
[LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...
- [LOJ 6030]「雅礼集训 2017 Day1」矩阵
[LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...
- [LOJ 6029]「雅礼集训 2017 Day1」市场
[LOJ 6029] 「雅礼集训 2017 Day1」市场 题意 给定一个长度为 \(n\) 的数列(从 \(0\) 开始标号), 要求执行 \(q\) 次操作, 每次操作为如下四种操作之一: 1 l ...
- Loj #6503. 「雅礼集训 2018 Day4」Magic
Loj #6503. 「雅礼集训 2018 Day4」Magic 题目描述 前进!前进!不择手段地前进!--托马斯 · 维德 魔法纪元元年. 1453 年 5 月 3 日 16 时,高维碎片接触地球. ...
- LOJ #6509. 「雅礼集训 2018 Day7」C
神仙题 LOJ #6509 题意 给定一棵树,点权为0/1,每次随机一个点(可能和之前所在点相同)走到该点并将其点权异或上1 求期望的移动距离使得所有点点权相同 题解 根本不会解方程 容易发现如果一个 ...
- loj 6031「雅礼集训 2017 Day1」字符串
loj 注意到每次询问串长度都是给定的,并且询问串长\(k*\)询问次数\(q<10^5\),所以这里面一个东西大的时候另一个东西就小,那么考虑对较小的下功夫 如果\(k\le \sqrt{n} ...
- loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)
题意 链接 Sol \(10^5\)次询问每次询问\(10^5\)个区间..这种题第一感觉就是根号/数据分治的模型. \(K\)是个定值这个很关键. 考虑\(K\)比较小的情况,可以直接暴力建SAM, ...
- loj#6030. 「雅礼集训 2017 Day1」矩阵(贪心 构造)
题意 链接 Sol 自己都不知道自己怎么做出来的系列 不难观察出几个性质: 最优策略一定是先把某一行弄黑,然后再用这一行去覆盖不是全黑的列 无解当且仅当无黑色.否则第一个黑色所在的行\(i\)可以先把 ...
- loj#6029. 「雅礼集训 2017 Day1」市场(线段树)
题意 链接 Sol 势能分析. 除法是不能打标记的,所以只能暴力递归.这里我们加一个剪枝:如果区间内最大最小值的改变量都相同的话,就变成区间减. 这样复杂度是\((n + mlogn) logV\)的 ...
随机推荐
- SharePoint中用Power shell命令设置文档库列表的权限
首先停止继承权限 $web = Get-PnPweb $spoList= Get-PnPList "Testlist" -Web $web (注释:获取对象)$spoList.Br ...
- 使用jQuery开发tab选项卡插件
为了复习巩固jQuery的插件开发.HTML和CSS方面的知识,做了一个简单的tab选项卡插件,简单记录一下开发.使用的过程,以备日后使用. 一.插件效果 tab选项卡插件常用的功能均已实现,包括:动 ...
- Vue项目中遇到的问题汇总
一.打包后的打开index.html页面空白的几种情况: 引入的css.js路径报错,此时解决方法:把vue.config.js中的增加publicPath: ‘./’ 或者把原来的baseUrl改为 ...
- 怎么让自己的本地php网站让别人访问到
怎么样才能把本地的web网站项目让别人访问到呢?我来给分享一下. 第一:下载jnat工具: 第二:注册一个key; 第三:jnat工具初始化(一键注册本地的Apache+PHP环境): 第四:在jna ...
- Chrome快捷键统计
Chrome快捷键: Chrome 个人常用快捷键 1 将当前网页保存为书签 Ctrl + d 2 重新加载当前网页 Ctrl + r或F5 3 打开书签管理器 Ctrl + Shift + o 4 ...
- centos7安装nginx 并启动
原文连接 https://www.cnblogs.com/jerrypro/p/7062101.html 一.安装准备 首先由于nginx的一些模块依赖一些lib库,所以在安装nginx之前,必须先 ...
- 让 Python 代码更易维护的七种武器——代码风格(pylint、Flake8、Isort、Autopep8、Yapf、Black)测试覆盖率(Coverage)CI(JK)
让 Python 代码更易维护的七种武器 2018/09/29 · 基础知识 · 武器 原文出处: Jeff Triplett 译文出处:linux中国-Hank Chow 检查你的代码的质 ...
- Java精通并发-轻量级锁与重量级锁的变化深入详解
在上一次https://www.cnblogs.com/webor2006/p/11446129.html的理论的最后谈到了锁的演化,如下: 下面具体来阐述一下: 偏向锁:它是针对一个线程来说, 它的 ...
- Ajax -异步请求 -jquery中ajax分类 -第一层 $.ajax -第二层($.get /$.post) -第三层($.getJson/$.getScript) -相应演示
Ajax 1.标准请求响应时浏览器的动作(同步操作) 1.1浏览器请求什么资源,跟随显示什么资源2.ajax:异步请求. 2.1局部刷新,通过异步请求,请求到服务器资源数据后,通过脚本修改页面中部分内 ...
- P2577 [ZJOI2005]午餐[DP]
题目描述 上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂.这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭.由于每个人的口味(以及胃口)不同,所以他们要吃的菜各 ...