zoukankan      html  css  js  c++  java
  • 题解 P6516 【[QkOI#R1] Quark and Graph】

    题意

    给出一张(n)个点、(m)条边构成的无向图,已知(1)号点到各定点的最短距离(d_i),求方案数(对(998244353)取模)

    (t_i=sum_j[d_j=i]),还应满足(sum_{i}t_it_{i-1}le 2 imes 10^5)

    题解

    这里提供一种大常数的(mathcal{O}(nlog^2n))做法,大佬轻喷。

    首先题目里处处是提示, 观察数据范围,考虑建一张分层图,那么可以把边分成两部分:

    • 从前一层到后一层的
    • 在一层中连来连去的

    那么考虑生成函数。对于前一部分,考虑两个之间的生成函数为(1+x),那么(t_i)个到一个的生成函数为((1+x)^{t_i}),但因为不能不连边,常数项强制为(0),即((1+x)^{t_i}-1)。那么连到(t_{i+1})在次方就行了。

    于是对于第一部分生成函数有:

    [prod_{i=0}^{max(d)-1}((1+x)^{t_i}-1)^{t_{i+1}} ]

    这个我们可以(ln)+(exp)实现快速幂,在分治死算得到。直接copy模板即可。

    第二部分一共有(sum_{i=0}^{max(d)} binom{t_i}{2})条边可选,因此生成函数是

    [(1+x)^{sum_{i=0}^{max(d)} binom{t_i}{2}} ]

    用一下上面的板子就ok了。

    代码

    贴上菜鸡的大常数代码,仅供对拍...

    #include<bits/stdc++.h>
    namespace in{
    	char buf[1<<21],*p1=buf,*p2=buf;
    	inline int getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    	template <typename T>inline void read(T& t){
    		t=0;int f=0;char ch=getc();while (!isdigit(ch)){if(ch=='-')f = 1;ch=getc();}
    	    while(isdigit(ch)){t=t*10+ch-48;ch = getc();}if(f)t=-t;
    	}
    	template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
    }
    namespace out{
    	char buffer[1<<21];int p1=-1;const int p2 = (1<<21)-1;
    	inline void flush(){fwrite(buffer,1,p1+1,stdout),p1=-1;}
    	inline void putc(const char &x) {if(p1==p2)flush();buffer[++p1]=x;}
    	template <typename T>void write(T x) {
    		static char buf[15];static int len=-1;if(x>=0){do{buf[++len]=x%10+48,x/=10;}while (x);}else{putc('-');do {buf[++len]=-(x%10)+48,x/=10;}while(x);}
    		while (len>=0)putc(buf[len]),--len;
    	}
    }
    using namespace std;
    template<const int mod>
    struct modint{
        int x;
        modint<mod>(int o=0){x=o;}
        modint<mod> &operator = (int o){return x=o,*this;}
        modint<mod> &operator +=(modint<mod> o){return x=x+o.x>=mod?x+o.x-mod:x+o.x,*this;}
        modint<mod> &operator -=(modint<mod> o){return x=x-o.x<0?x-o.x+mod:x-o.x,*this;}
        modint<mod> &operator *=(modint<mod> o){return x=1ll*x*o.x%mod,*this;}
        modint<mod> &operator ^=(int b){
            modint<mod> a=*this,c=1;
            for(;b;b>>=1,a*=a)if(b&1)c*=a;
            return x=c.x,*this;
        }
        modint<mod> &operator /=(modint<mod> o){return *this *=o^=mod-2;}
        modint<mod> &operator +=(int o){return x=x+o>=mod?x+o-mod:x+o,*this;}
        modint<mod> &operator -=(int o){return x=x-o<0?x-o+mod:x-o,*this;}
        modint<mod> &operator *=(int o){return x=1ll*x*o%mod,*this;}
        modint<mod> &operator /=(int o){return *this *= ((modint<mod>(o))^=mod-2);}
    	template<class I>friend modint<mod> operator +(modint<mod> a,I b){return a+=b;}
        template<class I>friend modint<mod> operator -(modint<mod> a,I b){return a-=b;}
        template<class I>friend modint<mod> operator *(modint<mod> a,I b){return a*=b;}
        template<class I>friend modint<mod> operator /(modint<mod> a,I b){return a/=b;}
        friend modint<mod> operator ^(modint<mod> a,int b){return a^=b;}
        friend bool operator ==(modint<mod> a,int b){return a.x==b;}
        friend bool operator !=(modint<mod> a,int b){return a.x!=b;}
        bool operator ! () {return !x;}
        modint<mod> operator - () {return x?mod-x:0;}
    	modint<mod> &operator++(int){return *this+=1;}
    };
    const int N=4e6+5;
    
    const int mod=998244353;
    const modint<mod> GG=3,Ginv=modint<mod>(1)/3,I=86583718;
    struct poly{
    	vector<modint<mod>>a;
    	modint<mod>&operator[](int i){return a[i];}
    	int size(){return a.size();}
    	void resize(int n){a.resize(n);}
    	void reverse(){std::reverse(a.begin(),a.end());}
    	void print(){for(int i=0;i<a.size();i++)printf("%d ",a[i].x);puts("");}
    };
    int rev[N];
    inline int ext(int n){int k=0;while((1<<k)<n)k++;return k;}
    inline void init(int k){int n=1<<k;for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));}
    inline void ntt(poly&a,int k,int typ){
    	int n=1<<k;
    	for(int i=0;i<n;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int mid=1;mid<n;mid<<=1){
    		modint<mod> wn=(typ>0?GG:Ginv)^((mod-1)/(mid<<1));
    		for(int r=mid<<1,j=0;j<n;j+=r){
    			modint<mod> w=1;
    			for(int k=0;k<mid;k++,w=w*wn){
    				modint<mod> x=a[j+k],y=w*a[j+k+mid];
    				a[j+k]=x+y,a[j+k+mid]=x-y;
    			}
    		}
    	}
    	if(typ<0){
    		modint<mod> inv=modint<mod>(1)/n;
    		for(int i=0;i<n;i++)a[i]*=inv;
    	}
    }
    inline poly one(){poly a;a.a.push_back(1);return a;}
    poly operator +(poly a,poly b){
    	int n=max(a.size(),b.size());a.resize(n),b.resize(n);
    	for(int i=0;i<n;i++)a[i]+=b[i];return a;
    }
    poly operator -(poly a,poly b){
    	int n=max(a.size(),b.size());a.resize(n),b.resize(n);
    	for(int i=0;i<n;i++)a[i]-=b[i];return a;
    }
    inline poly operator*(poly a,poly b){
    	int n=a.size()+b.size()-1,k=ext(n);
    	a.resize(1<<k),b.resize(1<<k),init(k);
    	ntt(a,k,1);ntt(b,k,1);for(int i=0;i<(1<<k);i++)a[i]*=b[i];
    	ntt(a,k,-1),a.resize(n);return a;
    }
    inline poly operator*(poly a,modint<mod> b){for(int i=0;i<a.size();i++)a[i]*=b;return a; }
    inline poly operator/(poly a,modint<mod> b){for(int i=0;i<a.size();i++)a[i]/=b;return a; }
    inline poly operator-(poly a){for(int i=0;i<a.size();i++)a[i]=-a[i];return a; }
    poly inv(poly F,int k){
    	int n=1<<k;F.resize(n);
    	if(n==1){F[0]=modint<mod>(1)/F[0];return F;}
    	poly G,H=inv(F,k-1);
    	G.resize(n),H.resize(n<<1),F.resize(n<<1);
    	for(int i=0;i<n/2;i++)G[i]=H[i]*2;
    	init(k+1),ntt(H,k+1,1),ntt(F,k+1,1);
    	for(int i=0;i<(n<<1);i++)H[i]=H[i]*H[i]*F[i];
    	ntt(H,k+1,-1),H.resize(n);
    	for(int i=0;i<n;i++)G[i]-=H[i];return G;
    }
    inline poly inv(poly a){
    	int n=a.size();
    	a=inv(a,ext(n)),a.resize(n);return a;;
    }
    inline poly deriv(poly a){//求导 
    	int n=a.size()-1;
    	for(int i=0;i<n;i++)a[i]=a[i+1]*(i+1);
    	a.resize(n);return a;
    }
    inline poly inter(poly a){//求原 
    	int n=a.size()+1;a.resize(n);
    	for(int i=n;i>=1;i--)a[i]=a[i-1]/i;
    	a[0]=0;return a;
    }
    inline poly ln(poly a){
    	int n=a.size();
    	a=inter(deriv(a)*inv(a));
    	a.resize(n);return a;
    }
    poly exp(poly a,int k){
    	int n=1<<k;a.resize(n);
    	if(n==1)return one();
    	poly f0=exp(a,k-1);f0.resize(n);
    	return f0*(one()+a-ln(f0)); 
    }
    poly exp(poly a){
    	int n=a.size();
    	a=exp(a,ext(n));a.resize(n);return a;
    }
    inline poly pow(poly a,modint<mod> k){//保证a[0]=1 
    	a=ln(a);for(int i=0;i<a.size();i++)a[i]*=k.x;
    	return exp(a);
    }
    struct modpair{
    	//用于快速幂中的次数
    	modint<mod>k1;modint<mod-1>k2;
    	struct trueint{
    		double lg;int x;
     		trueint &operator=(int o){return x=o,lg=log10(o),*this;}
     		trueint &operator+=(int o){return lg<=8&&(x+=o,lg=log10(x)),*this;}
    		trueint &operator*=(int o){return x*=o,lg+=log10(o),*this;}
    	}k3;
    	modpair(modint<mod>_1,modint<mod-1>_2,trueint _3):k1(_1),k2(_2),k3(_3){}
    	modpair(int o=0){k1=o,k2=o,k3=o;}
        modpair &operator = (int o){return k1=o,k2=o,k3=o,*this;}
        modpair &operator +=(int o){return k1+=o,k2+=o,k3+=o,*this;}
        modpair &operator *=(int o){return k1*=o,k2*=o,k3*=o,*this;}
        friend modpair operator +(modpair a,int o){return a+=o;}
        friend modpair operator *(modpair a,int o){return a*=o;}
        modpair operator-(){return modpair(k1,k2,k3);}
    };
    inline poly pow2(poly a,modpair m){//不保证a[0]=1 
    	int k=0;modint<mod> val;
    	while(a[k]==0&&k<a.size())k++;
    	if(k==a.size()||k!=0&&m.k3.lg>8||1ll*m.k3.x*k>=a.size()){
    	for(int i=0;i<a.size();i++)a[i]=0;return a;}//bye~
    	val=a[k];poly b;b.resize(a.size()-k);
    	for(int i=0;i<b.size();i++)b[i]=a[i+k]/val;
    	b=pow(b,m.k1);for(int i=0;i<a.size();i++)a[i]=0;
    	for(int i=0;i<b.size()&&i+k*m.k1.x<a.size();i++)
    		a[i+k*m.k1.x]=b[i]*(val^m.k2.x);
    	return a;
    }
    int n,m,t[N],M;
    #define mid (l+r>>1)
    poly solve(int l,int r){
    	if(l==r){
    		//((1+x)^t[l]-1)^t[l+1]
    		//printf("%d,%d
    ",l,r);
    		poly F;F.resize(t[l]*t[l+1]+1);
    		F[0]=F[1]=1;F=pow(F,t[l]);F[0]=0;
    		//F.print();
    		F=pow2(F,modpair(t[l+1]));
    		//F.print();
    		return F;
    	}
    	poly F=solve(l,mid)*solve(mid+1,r);
    	//printf("%d,%d
    ",l,r);
    	if(F.size()>=m+1)F.resize(m+1);
    	//F.print();
    	return F;
    }
    #define C(x) (1ll*(x)*((x)-1)/2)
    signed main(){
    	in::read(n,m);for(int i=1,d;i<=n;i++)in::read(d),t[d]++,M=max(M,d);
    	poly f=solve(0,M-1),g;g.resize(m+1);g[0]=g[1]=1;
    	//for(int i=0;i<f.size();i++)printf("%d ",f[i].x);puts("");
    	modint<mod>T=0;for(int i=0;i<=n;i++)T+=C(t[i]);
    	f=f*pow(g,T);out::write(f[m].x);
    	out::flush();
    	return 0;
    }
    
  • 相关阅读:
    PAT1007
    PAT1005
    PAT1002
    PAT1003
    PAT1016
    PAT 1018
    PAT1009
    pat 1037
    解决Git合并分支发生的冲突
    站和队列的基本使用
  • 原文地址:https://www.cnblogs.com/juruo-cjl/p/14319258.html
Copyright © 2011-2022 走看看