zoukankan      html  css  js  c++  java
  • [gdoi2018 day1]小学生图论题【分治NTT】

    正题


    题目大意

    一张随机的(n)个点的竞赛图,给出它的(m)条相互无交简单路径,求这张竞赛图的期望强联通分量个数。

    (1leq n,mleq 10^5)


    解题思路

    先考虑(m=0)的做法,此时我们考虑一个强联通块的贡献,注意到竞赛图中强联通块的会构成一条链的形式,枚举一个大小(S),那么此时联通块内到联通块外的边方向确定,那么这个联通块产生贡献的的概率就是(frac{1}{2}^{S(n-S)}),选出这个联通块的方案就是(inom{n}{i})
    那么答案就是

    [sum_{i=1}^nfrac 1 2^{S(n-S)}inom{n}{i} ]

    考虑包含给出路径的情况,因为无交,所以点的编号不影响答案,只有路径长度影响方案。

    考虑一条路径对一个强联通分量造成的贡献,考虑如果一条链的一半在这个块内,一条在这个块外,那么就会确定一条边的方案。所以除数要除以(2)

    把单点看成链的话,那么一个块由多条链组成,对于每条链构建一个形如

    [1+2x+2x^2+...+2x^{l-1}+x^{l-1} ]

    的多项式,然后跑分治(NTT)乘起来再用上面的式子做就好了。

    时间复杂度(O(nlog^2 n))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    #define ll long long
    using namespace std;
    const ll N=4e5+10,T=20,P=998244353;
    struct Poly{
    	ll a[N],n;
    }F[T];
    ll n,m,a[N],r[N],x[N],y[N];
    bool v[T];
    ll read(){
    	ll x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    ll power(ll x,ll b){
    	ll ans=1;
    	while(b){
    		if(b&1)ans=ans*x%P;
    		x=x*x%P;b>>=1;
    	}
    	return ans;
    }
    void NTT(ll *f,ll n,ll op){
    	for(ll i=0;i<n;i++)
    		if(i<r[i])swap(f[i],f[r[i]]);
    	for(ll p=2;p<=n;p<<=1){
    		ll tmp=power(3,(P-1)/p),len=p>>1;
    		if(op==-1)tmp=power(tmp,P-2);
    		for(ll k=0;k<n;k+=p){
    			ll buf=1;
    			for(ll i=k;i<k+len;i++){
    				ll tt=buf*f[i+len]%P;
    				f[i+len]=(f[i]-tt+P)%P;
    				f[i]=(f[i]+tt)%P;
    				buf=buf*tmp%P;
    			}
    		}
    	}
    	if(op==-1){
    		ll invn=power(n,P-2);
    		for(ll i=0;i<n;i++)
    			f[i]=f[i]*invn%P;
    	}
    	return;
    }
    void Mul(Poly &F,Poly &G){
    	ll n=1;
    	while(n<F.n+G.n)n<<=1;
    	for(ll i=0;i<F.n;i++)x[i]=F.a[i];
    	for(ll i=0;i<G.n;i++)y[i]=G.a[i];
    	for(ll i=F.n;i<n;i++)x[i]=0;
    	for(ll i=G.n;i<n;i++)y[i]=0;
    	for(ll i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)?(n>>1):0);
    	NTT(x,n,1);NTT(y,n,1);
    	for(ll i=0;i<n;i++)x[i]=x[i]*y[i]%P;
    	NTT(x,n,-1);
    	for(ll i=0;i<n;i++)F.a[i]=x[i];
    	F.n=F.n+G.n-1;return; 
    }
    ll Find(){
    	for(ll i=0;i<T;i++)
    		if(!v[i]){v[i]=1;return i;}
    }
    ll Solve(ll l,ll r){
    	if(l==r){
    		ll p=Find();F[p].a[0]=1;F[p].a[a[l]]=1;
    		for(ll i=1;i<a[l];i++)F[p].a[i]=2;
    		F[p].n=a[l]+1;return p;
    	}
    	ll mid=(l+r)>>1;
    	ll ls=Solve(l,mid),rs=Solve(mid+1,r);
    	Mul(F[ls],F[rs]);v[rs]=0;
    	return ls;
    }
    signed main()
    {
    	freopen("graph.in","r",stdin);
    	freopen("graph.out","w",stdout);
    	n=read();m=read();
    	ll sum=n,ans=0;
    	for(ll i=1;i<=m;i++){
    		a[i]=read();sum-=a[i];
    		for(ll j=1,x;j<=a[i];j++)x=read();
    	}
    	while(sum)
    		a[++m]=1,sum--;
    	ll p=Solve(1,m);
    	for(ll i=0;i<n;i++)
    		(ans+=F[p].a[i]*power((P+1)/2,i*(n-i))%P)%=P;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    SCI写作经典替换词,瞬间高大上!(转)
    最佳化常用测试函数 Optimization Test functions
    算法复杂度速查表
    VS 代码行统计
    CPLEX IDE 菜单栏语言设置( 中文 英文 韩文 等多国语言 设置)
    如何从PDF文件中提取矢量图
    Matlab无法打开M文件的错误( Undefined function or method 'uiopen' for input arguments of type 'char)
    visual studio 资源视图 空白 解决方案
    MFC DialogBar 按钮灰色不响应
    嗨翻C语言笔记(二)
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15195333.html
Copyright © 2011-2022 走看看