• 「HDU6593」Coefficient


    题目

    点这里看题目。

    在后 open-hdu 的时代,我只能挂一个 vjudge 的链接充数了。

    分析

    首先观察到,和 \(x\) 具体关联的部分是 \(e^{ax+d}\);而且我们还需要在 \(x_0=-\frac d a\) 处展开,这不是明示换元吗?

    \(t=ax+d,g(t)=\frac{b}{e^t+c}\),则有 \(f(x)=g(t)\),且我们还有 \(\frac{f^{(n)}(x_0)}{n!}=a^n\frac{g^{(n)}(0)}{n!}\)

    事实上,由于我们这里不考虑收敛性,我们可以直接把 \(g(t)\) 当作形式幂级数处理,来求出它的 \([t^n]\)。这个结果便是所需的 \(\frac{g^{(n)}(0)}{n!}\)

    Note.

    通常而言,封闭形式对应的完整的形式幂级数,对应的是它的麦克劳林级数。

    观察一下特殊情况:如果 \(c=-1\),则 \(g(0)\) 未定义,我们没有办法在 \(t_0=0\) 处展开它。因此,这种情况应当输出 \(-1\)

    在剩下的情况中,我们用一点小技巧,把整个问题转化成复合 \(e^x-1\) 的形式,也就是求 \([t^n]\frac{b}{(e^t-1)+(c+1)}\)。进一步的变形得到 \([t^n]\frac{\frac{b}{c+1}}{1-(-\frac{e^t-1}{c+1})}\),然后展开:

    \[\begin{aligned} [t^n]\frac{1}{1-(-\frac{e^t-1}{c+1})} &=[t^n]\sum_{k\ge 0}\left(-\frac{1}{c+1}\right)^k(e^t-1)^k\\ &=[t^n]\sum_{k=0}^{\bold{n}}\left(-\frac{1}{c+1}\right)^k\sum_{j=0}^k\binom{k}{j}e^{jt}(-1)^{k-j}\\ &=\sum_{k=0}^{n}\left(-\frac{1}{c+1}\right)^k\sum_{j=0}^k\binom{k}{j}\frac{j^n}{n!}(-1)^{k-j}\\ \end{aligned} \]

    这样的技巧的优秀之处在加粗的 \(n\) 处完全体现出来了。

    Note.

    事实是,构造良好的复合是一种很好的处理方法。

    比如,你可能想问,为什么我们不选择直接展开成 \(\frac{\frac{b}{c}}{1-\left(-\frac{e^t}{c}\right)}\) 呢?

    因为,这个时候复合的函数 \(-\frac{e^t}{c}\) 的级数形式不仅没有求和上界,还有常数项。这样的复合,实际上不够“良定义”的,是违背历史规律的行为。

    那为什么 tly 直接复合 \(e^x\) 并解决本题呢?我想,这必然是因为祂是神,可以不受任何规律限制随心所欲地使用任何方式解决任何问题


    其它的例子包括斯特林数处理幂和问题。斯特林数的生成函数是:

    \[\exp(y(e^x-1)) \]

    当我们具体处理幂和的时候,我们只需要强行将 \(e^x\) 拆成 \((e^x-1)+1\),就可以得到斯特林数,并且还顺便缩减了求和的界。

    接下来,我们可以注意到,第二个 \(\sum\) 里面的内容和 \(c\) 完全没有关系,则这实际上是关于 \(-\frac 1{c+1}\) 的多项式函数。算多项式的系数可以卷积处理,而算多次点值直接多点求值就好啦!

    时间复杂度是 \(O(q\log^2 q)\)

    代码

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    
    #define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
    #define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
    
    const int mod = 998244353;
    const int MAXN = ( 1 << 17 ) + 5;
    
    template<typename _T>
    void read( _T &x ) {
    	x = 0; char s = getchar(); int f = 1;
    	while( ! ( '0' <= s && s <= '9' ) ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
    	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
    	x *= f;
    }
    
    template<typename _T>
    void write( _T x ) {
    	if( x < 0 ) putchar( '-' ), x = -x;
    	if( 9 < x ) write( x / 10 );
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    inline _T Max( const _T &a, const _T &b ) {
    	return a > b ? a : b;
    }
    
    typedef std :: vector<int> Poly;
    
    int fac[MAXN], ifac[MAXN];
    
    Poly prod[MAXN << 2];
    int ans[MAXN], xVal[MAXN], id[MAXN];
    
    Poly U, V, F;
    
    int N, Q, M;
    
    inline int Qkpow( int, int );
    inline int Inv( const int &a ) { return Qkpow( a, mod - 2 ); }
    inline int Mul( int x, const int &v ) { return 1ll * x * v % mod; }
    inline int Sub( int x, const int &v ) { return ( x -= v ) < 0 ? x + mod : x; }
    inline int Add( int x, const int &v ) { return ( x += v ) >= mod ? x - mod : x; }
    
    inline int& MulEq( int &x, const int &v ) { return x = 1ll * x * v % mod; }
    inline int& SubEq( int &x, const int &v ) { return ( x -= v ) < 0 ? ( x += mod ) : x; }
    inline int& AddEq( int &x, const int &v ) { return ( x += v ) >= mod ? ( x -= mod ) : x; }
    
    inline int Qkpow( int base, int indx ) {
    	int ret = 1;
    	while( indx ) {
    		if( indx & 1 ) MulEq( ret, base );
    		MulEq( base, base ), indx >>= 1;
    	}
    	return ret;
    }
    
    namespace Basics {
    	const int L = 17, g = 3, phi = mod - 1;
    
    	int w[MAXN];
    
    	inline void NTTInit( const int &n = 1 << L ) {
    		w[0] = 1, w[1] = Qkpow( g, phi >> L );
    		rep( i, 2, n - 1 ) w[i] = Mul( w[i - 1], w[1] );
    	}
    
    	inline void DIF( int *coe, const int &n ) {
    		int *wp, p, e, o;
    		for( int s = n >> 1 ; s ; s >>= 1 )
    			for( int i = 0 ; i < n ; i += s << 1 ) {
    				p = ( 1 << L ) / ( s << 1 ), wp = w;
    				for( int j = 0 ; j < s ; j ++, wp += p ) {
    					e = coe[i + j], o = coe[i + j + s];
    					coe[i + j] = Add( e, o );
    					coe[i + j + s] = Mul( *wp, Sub( e, o ) );
    				}
    			}
    	}
    
    	inline void DIT( int *coe, const int &n ) {
    		int *wp, p, k;
    		for( int s = 1 ; s < n ; s <<= 1 )
    			for( int i = 0 ; i < n ; i += s << 1 ) {
    				p = ( 1 << L ) / ( s << 1 ), wp = w;
    				for( int j = 0 ; j < s ; j ++, wp += p )
    					k = Mul( *wp, coe[i + j + s] ),
    					coe[i + j + s] = Sub( coe[i + j], k ),
    					coe[i + j] = Add( coe[i + j], k );
    			}
    		std :: reverse( coe + 1, coe + n );
    		int inv = Inv( n ); rep( i, 0, n - 1 ) MulEq( coe[i], inv );
    	}
    }
    
    namespace Operation {
    	inline Poly PlusMul( const Poly &A, const Poly &B, const int &rem ) {
    		static int P[MAXN] = {}, Q[MAXN] = {};
    
    		int n = A.size(), m = B.size(), L;
    		for( L = 1 ; L <= n + m - 2 ; L <<= 1 );
    		rep( i, 0, L - 1 ) P[i] = Q[i] = 0;
    		rep( i, 0, n - 1 ) P[i] = A[i];
    		rep( i, 0, m - 1 ) Q[i] = B[i];
    		Basics :: DIF( P, L );
    		Basics :: DIF( Q, L );
    		rep( i, 0, L - 1 ) MulEq( P[i], Q[i] );
    		Basics :: DIT( P, L ); Poly ret;
    		rep( i, 0, rem - 1 ) ret.push_back( P[i] );
    		return ret;
    	}
    
    	inline Poly SubMul( const Poly &A, const Poly &B, const int &rem ) {
    		static int P[MAXN] = {}, Q[MAXN] = {};
    
    		int n = A.size(), m = B.size(), L;
    		for( L = 1 ; L <= n + m - 2 ; L <<= 1 );
    		rep( i, 0, L - 1 ) P[i] = Q[i] = 0;
    		rep( i, 0, n - 1 ) P[i] = A[i];
    		rep( i, 0, m - 1 ) Q[i] = B[i];
    		std :: reverse( Q, Q + m );
    		Basics :: DIF( P, L );
    		Basics :: DIF( Q, L );
    		rep( i, 0, L - 1 ) MulEq( P[i], Q[i] );
    		Basics :: DIT( P, L ); Poly ret;
    		rep( i, 0, rem - 1 ) ret.push_back( P[i + m - 1] );
    		return ret;
    	}
    }
    
    namespace PolyInv {
    	int P[MAXN], Q[MAXN], U[MAXN], V[MAXN];
    
    	void Newton( const int &n ) {
    		if( n == 1 ) {
    			U[0] = Inv( P[0] );
    			return ;
    		}
    		int h = ( n + 1 ) >> 1, L; Newton( h );
    		for( L = 1 ; L <= n + h - 2 ; L <<= 1 );
    		rep( i, 0, L - 1 ) Q[i] = V[i] = 0;
    		rep( i, 0, n - 1 ) Q[i] = P[i];
    		rep( i, 0, h - 1 ) V[i] = U[i];
    		Basics :: DIF( Q, L );
    		Basics :: DIF( V, L );
    		rep( i, 0, L - 1 ) Q[i] = Mul( V[i], Sub( 2, Mul( V[i], Q[i] ) ) );
    		Basics :: DIT( Q, L );
    		rep( i, h, n - 1 ) U[i] = Q[i];
    	}
    
    	inline Poly PolyInv( const Poly &A, const int &rem ) {
    		int n = A.size();
    		rep( i, 0, rem - 1 ) P[i] = 0;
    		rep( i, 0, n - 1 ) P[i] = A[i];
    		Newton( rem ); Poly ret;
    		rep( i, 0, rem - 1 ) ret.push_back( U[i] );
    		return ret;
    	}
    }
    
    inline void Init( const int &n = 1 << 17 ) {
    	fac[0] = 1; rep( i, 1, n ) fac[i] = Mul( fac[i - 1], i );
    	ifac[n] = Inv( fac[n] ); per( i, n - 1, 0 ) ifac[i] = Mul( ifac[i + 1], i + 1 );
    }
    
    void Divide( const int &x, const int &l, const int &r ) {
    	using namespace Operation;
    
    	if( l > r ) return ;
    	if( l == r ) {
    		prod[x].clear(), prod[x].resize( 2 );
    		prod[x][0] = 1, prod[x][1] = Mul( mod - 1, xVal[l] );
    		return ;
    	}
    	int mid = ( l + r ) >> 1;
    	Divide( x << 1, l, mid );
    	Divide( x << 1 | 1, mid + 1, r );
    	prod[x] = PlusMul( prod[x << 1], prod[x << 1 | 1], r - l + 2 );
    }
    
    void Redivide( const int &x, const int &l, const int &r, const Poly &cur ) {
    	using namespace Operation;
    
    	if( l > r ) return ;
    	if( l == r ) { MulEq( ans[id[l]], cur[0] ); return ; }
    	int mid = ( l + r ) >> 1;
    	Redivide( x << 1, l, mid, SubMul( cur, prod[x << 1 | 1], mid - l + 2 ) );
    	Redivide( x << 1 | 1, mid + 1, r, SubMul( cur, prod[x << 1], r - mid + 1 ) );
    }
    
    int main() {
    	freopen( "coe.in", "r", stdin );
    	freopen( "coe.out", "w", stdout );
    	Init();
    	Basics :: NTTInit();
    	while( ~ scanf( "%d %d", &N, &Q ) ) {
    		U.clear(), V.clear();
    		U.resize( N + 1 ), V.resize( N + 1 );
    		rep( i, 0, N ) {
    			U[i] = Mul( Qkpow( i, N ), ifac[i] );
    			V[i] = i & 1 ? Mul( mod - 1, ifac[i] ) : ifac[i];
    		}
    		F = Operation :: PlusMul( U, V, N + 1 );
    		rep( i, 0, N ) MulEq( F[i], fac[i] );
    		M = 0;
    		rep( i, 1, Q ) {
    			int a, b, c, d;
    			read( a ), read( b );
    			read( c ), read( d );
    			a = ( a % mod + mod ) % mod;
    			b = ( b % mod + mod ) % mod;
    			c = ( c % mod + mod ) % mod;
    			d = ( d % mod + mod ) % mod;
    			if( c == mod - 1 ) ans[i] = -1;
    			else {
    				ans[i] = Mul( Mul( Qkpow( a, N ), Mul( b, Inv( Add( c, 1 ) ) ) ), ifac[N] );
    				M ++, xVal[M] = Mul( mod - 1, Inv( Add( c, 1 ) ) ), id[M] = i;
    			}
    		}
    		Divide( 1, 1, M );
    		U = PolyInv :: PolyInv( prod[1], Max( M + 1, N + 1 ) );
    		F = Operation :: SubMul( F, U, M + 1 );
    		Redivide( 1, 1, M, F );
    		rep( i, 1, Q ) write( ans[i] ), putchar( '\n' );
    	}
    	return 0;
    }
    
  • 相关阅读:
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 实现业务
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 开发流程
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 报表系统集成说明
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 处理报表
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 数据访问
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 分布式应用
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 实现插件
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 对象设计器使用帮助
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 数据层开发
    Jquery 中的CheckBox、 RadioButton、 DropDownList、CheckBoxList、RadioButtonList的取值赋值
  • 原文地址:https://www.cnblogs.com/crashed/p/16422174.html
Copyright © 2020-2023  润新知