ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LOJ6496 「雅礼集训 2018 Day1」仙人掌

2020-06-08 22:57:17  阅读:333  来源: 互联网

标签:std return int void Day1 i64 雅礼 2018 include


Link
先考虑树的情况,设\(f_{u,0/1}\)表示\(u\)的父亲占用的\(u\)的出度为\(0/1\)的情况下给\(u\)的子树内的边定向的方案数。
转移很简单,这里就不赘述了。
现在考虑仙人掌的情况,考虑在圆方树上dp。
状态需要改为\(f_{u,0/1/2}\),圆点可以用类似于树上的形式dp,方点可以枚举环上任意一条边的方向然后递推。
这个dp的形式类似于背包,可以用分治NTT优化。

#include<cctype>
#include<cstdio>
#include<vector>
#include<cstring>
#include<utility>
#include<algorithm>
using i64=long long;
using pi=std::pair<int,int>;
using poly=std::vector<i64>;
const int N=100007,M=1<<18,P=998244353;
char ibuf[1<<22],*iS=ibuf;int n,m,len,deg,rev[M],a[N],fa[N];i64 w[M],f[N][3];
std::vector<pi>e[N];std::vector<poly>vec[N];
int read(){int x=0;while(isspace(*iS))++iS;while(isdigit(*iS))(x*=10)+=*iS++&15;return x;}
int getlen(int n){return 1<<(32-__builtin_clz(n));}
void inc(i64&a,i64 b){a+=b-P,a+=a>>63&P;}
void dec(i64&a,i64 b){a-=b,a+=a>>63&P;}
i64 pow(i64 a,i64 b){i64 r=1;for(;b;b>>=1,a=a*a%P)if(b&1)r=r*a%P;return r;}
void init(int n)
{
    int lim=1<<(len=32-__builtin_clz(n)),pos=lim/2;i64 g=pow(3,(P-1)/lim);
    for(int i=1;i<lim;++i) rev[i]=(rev[i>>1]>>1)|(i&1? pos:0);
    w[pos]=1;for(int i=pos+1;i<lim;++i) w[i]=g*w[i-1]%P;
    for(int i=pos-1;i;--i) w[i]=w[i<<1];
}
void NTT(i64*a,int lim,int f)
{
    if(!~f) std::reverse(a+1,a+lim);
    for(int i=0,x=len-__builtin_ctz(lim);i<lim;++i) if(i<rev[i]>>x) std::swap(a[i],a[rev[i]>>x]);
    for(int i=1;i<lim;i<<=1) for(int j=0,d=i<<1;j<lim;j+=d) for(int k=0,x;k<i;++k) x=w[i+k]*a[i+j+k]%P,dec(a[i+j+k]=a[j+k],x),inc(a[j+k],x);
    if(!~f) for(int i=0,x=P-(P-1)/lim;i<lim;++i) a[i]=x*a[i]%P;
}
poly operator*(poly a,poly b)
{
    int len=a.size()+b.size()-1,lim=getlen(len);
    a.resize(lim),NTT(&a[0],lim,1),b.resize(lim),NTT(&b[0],lim,1);
    for(int i=0;i<lim;++i) a[i]=a[i]*b[i]%P;
    return NTT(&a[0],lim,-1),a.resize(std::min(deg,len)),a;
}
#define mid ((l+r)/2)
poly solve(std::vector<poly>&a,int l,int r)
{
    if(l==r) return a[l];
    return solve(a,l,mid)*solve(a,mid+1,r);
}
#undef mid
void make_ring(int u,int v)
{
    static int cir[N];static i64 g[N][2],s[3];int cnt=s[0]=s[1]=s[2]=0;
    for(;u!=v;v=fa[v]) cir[++cnt]=v;
    for(int o=0;o<2;++o)
    {
	g[0][0]=o,g[0][1]=!o;
	for(int i=1,u;i<=cnt;++i) u=cir[i],g[i][0]=(g[i-1][0]*f[u][1]+g[i-1][1]*f[u][0])%P,g[i][1]=(g[i-1][0]*f[u][2]+g[i-1][1]*f[u][1])%P;
	inc(s[2-o],g[cnt][0]),inc(s[1-o],g[cnt][1]);
    }
    vec[u].push_back({s[0],s[1],s[2]});
}
void dfs(int u,int from)
{
    static int dfn[N],low[N],tim;dfn[u]=low[u]=++tim;
    for(auto[v,id]:e[u])
    {
	if(id==from) continue;
	if(!dfn[v])
	{
	    fa[v]=u,dfs(v,id),low[u]=std::min(low[u],low[v]);
	    if(dfn[v]==low[v]) vec[u].push_back({f[v][1],f[v][0]});
	}
	else if(low[u]=std::min(low[u],dfn[v]),dfn[v]>dfn[u]) make_ring(u,v);
    }
    if(vec[u].empty()) {for(int i=0;i<3;++i)f[u][i]=a[u]>=i;return ;}
    deg=a[u]+1;
    poly g=solve(vec[u],0,(int)vec[u].size()-1);
    deg=std::min(deg,(int)g.size());
    for(int i=0;i<deg;++i) for(int j=0;j<3;++j) if(i+j<=a[u]) inc(f[u][j],g[i]);
}
int main()
{
    fread(ibuf,1,1<<22,stdin);
    n=read(),m=read(),init(2*n);
    for(int i=1,u,v;i<=m;++i) u=read(),v=read(),e[u].emplace_back(v,i),e[v].emplace_back(u,i);
    for(int i=1;i<=n;++i) a[i]=read();
    dfs(1,0),printf("%lld",f[1][0]);
}

标签:std,return,int,void,Day1,i64,雅礼,2018,include
来源: https://www.cnblogs.com/cjoierShiina-Mashiro/p/13069156.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有