CF923E Perpetual Subtraction

考虑每次转移前后的关系:

\(\displaystyle F(x)=\sum_{i=0}^nf_{i}x^i\) , \(F^*(x)\) 为操作后的生成函数。

\[\begin{aligned} F^*(x)&= \sum_{i=0}^n x^i\sum_{j=i}^n \frac{f_j}{j+1}\\ &= \sum_{i=0}^n \frac{f_i}{i+1}\sum_{j=0}^i x^j\\ &=\sum_{i=0}^n\frac{f_i}{i+1}\frac{1-x^{i+1}}{1-x} \\ &=\frac{1}{1-x}\sum_{i=0}^n\frac{f_i}{i+1}\left(1-x^{i+1} \right) \\ &=\frac{1}{x-1}\sum_{i=0}^n f_i\left(\frac{x^{i+1}-1^{i+1}}{i+1} \right) \\ &=\frac{1}{x-1}\sum_{i=0}^n f_i \int_{1}^x t^i ~\text{d}t \\ &=\frac{\int_{1}^x F(t)~ \text{d}t}{x-1} \end{aligned}\]

有一个自然的想法: 令 \(G(x-1)=F(x)\),那么有:

\[G^*(x)=F^*(x+1)=\frac{\int_0^xG(t) ~\text{d} t}{x} \]

又因为:

\[\int G(x)=\sum_{i=0}^n\frac{g_i}{i+1}x^{i+1}+C \]

得到:

\[G^*(x)=\sum_{i=0}^n \frac{g_i}{i+1}x^i \]

那么:

\[G_m(x)=\sum_{i=0}^n \frac{g_{0,i}}{(i+1)^m}x^i \]

显然有 \(\displaystyle F_0(x)=\sum_{i=0}^n p_ix^i\)

只需要知道 \(F,G\) 之间如何转换即可。

  • \(F \to G\)

\[\begin{aligned} G(x)&=F(x+1) \\ &=\sum_{i=0}^n f_i(x+1)^i \\ &=\sum_{i=0}^n f_i\sum_{j=0}^i \binom{i}{j} x^j\\ &=\sum_{j=0}^n x^j \sum_{i=j}^n \binom{i}{j}f_i \\ &=\sum_{j=0}^n x^j\frac{1}{j!}\sum_{i=j}^n \frac{f_ii!}{(i-j)!} \end{aligned}\]

反转 \(f_ii!\) 后便可得到卷积形式。

  • \(G \to F\)

\[\begin{aligned} F(x)&=G(x-1) \\ &=\sum_{i=0}^n g_i(x-1)^i \\ &=\sum_{i=0}^n g_i\sum_{j=0}^i \binom{i}{j} x^j(-1)^{i-j}\\ &=\sum_{j=0}^n x^j \sum_{i=j}^n \binom{i}{j}g_i (-1)^{i-j}\\ &=\sum_{j=0}^n x^j\frac{1}{j!}\sum_{i=j}^n g_ii!\frac{(-1)^{i-j}}{(i-j)!} \end{aligned}\]

同样反转 \(g_i i!\) 为卷积形式。

那么 \(F_0 \Rightarrow G_0\) , \(G_0 \Rightarrow G_m , G_m \Rightarrow F_m\) 即可

两次卷积转换 \(f,g\) ,时间复杂度 \(\mathcal{ O(n \log n ) }\)

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long

const int MAXN = 4e5 , Mod = 998244353;
int Add( int x , int y ) { x += y; return x >= Mod ? x - Mod : x; }
int Sub( int x , int y ) { x -= y; return x < 0 ? x + Mod : x; }
int Mul( int x , int y ) { return 1ll * x * y % Mod; }
int Quick_pow( int x , int po ) { int Ans = 1; for( ; po ; po >>= 1 , x = Mul( x , x ) ) if( po & 1 ) Ans = Mul( Ans , x ); return Ans; }
int Inv( int x ) { return Quick_pow( x , Mod - 2 ); }
int fac[ MAXN + 5 ] , ivf[ MAXN + 5 ];
void Init( ) {
	fac[ 0 ] = 1;
	for( int i = 1 ; i <= MAXN ; i ++ ) fac[ i ] = Mul( fac[ i - 1 ] , i );
	ivf[ MAXN ] = Inv( fac[ MAXN ] );
	for( int i = MAXN ; i >= 1 ; i -- ) ivf[ i - 1 ] = Mul( ivf[ i ] , i );
}

#define Poly vector< int >
#define len( x ) ( (int)x.size() )

const int G = 3 , IG = 332748118;
int lim , ilim , rev[ MAXN + 5 ];
void ntt( Poly &f , int op ) {
	for( int i = 0 ; i < lim ; i ++ ) if( i < rev[ i ] ) swap( f[ i ] , f[ rev[ i ] ] );
	for( int len = 2 , w ; len <= lim ; len <<= 1 ) {
		w = Quick_pow( op == 1 ? G : IG , ( Mod - 1 ) / len );
		for( int l = 0 ; l < lim ; l += len ) {
			for( int i = l , wk = 1 ; i < l + len / 2 ; i ++ , wk = Mul( wk , w ) ) {
				int t = Mul( wk , f[ i + len / 2 ] );
				f[ i + len / 2 ] = Sub( f[ i ] , t ); f[ i ] = Add( f[ i ] , t );
			}
		}
	}
	if( op == -1 ) for( int i = 0 ; i < lim ; i ++ ) f[ i ] = Mul( f[ i ] , ilim );
}
Poly operator * ( Poly f , Poly g ) {
	int n = len( f ) + len( g ) - 1; for( lim = 1 ; lim < n ; lim <<= 1 ); ilim = Inv( lim );
	for( int i = 0 ; i < lim ; i ++ ) rev[ i ] = ( rev[ i >> 1 ] >> 1 ) | ( i & 1 ? lim >> 1 : 0 );
	f.resize( lim ); g.resize( lim );
	ntt( f , 1 ); ntt( g , 1 );
	for( int i = 0 ; i < lim ; i ++ ) f[ i ] = Mul( f[ i ] , g[ i ] );
	ntt( f , -1 ); f.resize( n ); 
	return f;
}

int n; LL m;

Poly Solve( Poly f , int op ) {
	Poly g; g.resize( n + 1 );
	for( int i = 0 ; i <= n ; i ++ ) f[ i ] = Mul( f[ i ] , fac[ i ] );
	reverse( f.begin() , f.end() );
	for( int i = 0 ; i <= n ; i ++ ) g[ i ] = ( ( i & 1 ) && ( op == -1 ) ) ? Mod - ivf[ i ] : ivf[ i ];
	f = f * g; f.resize( n + 1 );
	reverse( f.begin() , f.end() );
	for( int i = 0 ; i <= n ; i ++ ) f[ i ] = Mul( f[ i ] , ivf[ i ] );
	return f;
}

Poly f;
int main( ) {
	Init();
	scanf("%d %lld",&n,&m); f.resize( n + 1 );
	for( int i = 0 ; i <= n ; i ++ ) scanf("%d", &f[ i ] );
	f = Solve( f , 1 );
	for( int i = 0 ; i <= n ; i ++ ) f[ i ] = Mul( f[ i ] , Inv( Quick_pow( i + 1 , m % ( Mod - 1 ) ) ) );
	f = Solve( f , -1 );
	for( int i = 0 ; i <= n ; i ++ ) printf("%d%c", f[ i ] , i == n + 1 ? '\n' : ' ' );
	return 0;
}
posted @ 2021-03-22 21:17  chihik  阅读(44)  评论(0编辑  收藏  举报