P5437 【XR-2】约定

每一条边被选中的概率: \(\frac{n-1}{\frac{n(n-1)}{2}}=\frac{2}{n}\)

所以答案为:

\[\frac{2}{n} \sum_{i=1}^{n-1} \sum_{j=i+1}^n (i+j)^k \]

单独考虑后面的和式:

\[f(n)=\sum_{i=1}^{n-1}\sum_{j=i+1}^n(i+j)^k \]

运用插值的套路:

\[\Delta (f)=f(n+1)-f(n)=\sum_{i=1}^n\sum_{j=i+1}^{n+1}(i+j)^k-\sum_{i=1}^{n-1}\sum_{j=i+1}^n(i+j)^k=\sum_{i=1}^n(i+n+1)^k=\sum_{i=n+2}^{2n+1}i^k \]

\(S(n)=\sum_{i=1}^n i^k\) ,那么有:

\[\Delta(f)=S(2n+1)-S(n+1) \]

老祖宗告诉我们 \(S\) 是一个 \(k+1\) 次多项式,那么 \(\Delta(f)\) 也是一个 \(k+1\) 次多项式, \(f\) 应该是一个 \(k+2\) 次多项式。

众所周知前 \(k\) 项的自然数幂和可以 \(\mathcal O(k)\) 预处理,那么暴力算出 \(f\)\(k+3\) 项的复杂度为 \(\mathcal O(k)\)

然后 \(\mathcal O(k)\) 插值即可。

做了这道题才发现自己 \(\mathcal O(k)\) 的插值是假的

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

const int MAXN = 20000010 , Mod = 998244353;

int Quick_pow( int x , int po ) {
	int Ans = 1;
	for( ; po ; po >>= 1 , x = 1ll * x * x % Mod )
		if( po & 1 ) Ans = 1ll * Ans * x % Mod;
	return Ans;
}
int Inv( int x ) {
	return ( Quick_pow( x , Mod - 2 ) + Mod ) % Mod;
}
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 Div( int x , int y ) { return 1ll * x * Inv( y ) % Mod; } 
int Fix( int x ) { return ( x % Mod + Mod ) % Mod; }

int fac[ MAXN + 5 ] , ivf[ MAXN + 5 ];
void Init( ) {
	fac[ 0 ] = 1;
	for( int i = 1 ; i <= min( MAXN , Mod - 1 ) ; i ++ ) fac[ i ] = Mul( fac[ i - 1 ] , i );
	ivf[ min( MAXN , Mod - 1 ) ] = Inv( fac[ min( MAXN , Mod - 1 ) ] );
	for( int i = min( MAXN , Mod - 1 ) ; i >= 1 ; i -- ) ivf[ i - 1 ] = Mul( ivf[ i ] , i );
}
int binom( int n , int m ) {
	if( n < m ) return 0;
	return Mul( fac[ n ] , Mul( ivf[ m ] , ivf[ n - m ] ) );
}

int n , k;

int prnum , prime[ MAXN + 5 ] , Sk[ MAXN + 5 ];
bool vis[ MAXN + 5 ];
void sieve( ) {
	Sk[ 1 ] = 1;
	for( int i = 2 ; i <= MAXN ; i ++ ) {
		if( !vis[ i ] ) { 
			prime[ ++ prnum ] = i;
			Sk[ i ] = Quick_pow( i , k );
		}
		for( int j = 1 ; j <= prnum && 1ll * i * prime[ j ] <= MAXN ; j ++ ) {
			vis[ i * prime[ j ] ] = 1;
			Sk[ i * prime[ j ] ] = Mul( Sk[ i ] , Sk[ prime[ j ] ] );
			if( i % prime[ j ] == 0 ) break;
		}
	}
	for( int i = 1 ; i <= MAXN ; i ++ ) Sk[ i ] = Add( Sk[ i ] , Sk[ i - 1 ] ); 
} 

int m;
int pre[ MAXN + 5 ] , suf[ MAXN + 5 ];
int Lagrange( int *fx , int x0 ) {
	pre[ 0 ] = 1;
	for( int i = 1 ; i <= m ; i ++ ) pre[ i ] = Mul( pre[ i - 1 ] , Sub( x0 , i ) );
	suf[ m + 1 ] = 1;
	for( int i = m ; i >= 1 ; i -- ) suf[ i ] = Mul( suf[ i + 1 ] , Sub( x0 , i ) );
	
	int fk = 0;
	for( int i = 1 ; i <= m ; i ++ ) fk = Add( fk , Mul( fx[ i ] , Mul( Mul( pre[ i - 1 ] , suf[ i + 1 ] ) , Fix( ( ( m - i ) & 1 ? -1 : 1 ) * Mul( ivf[ i - 1 ] , ivf[ m - i ] ) ) ) ) );
	return fk;
}
int y[ MAXN + 5 ];

int main( ) {
	Init();
	scanf("%d %d",&n,&k); m = k + 3;
	sieve();
	
	for( int i = 0 ; i < m ; i ++ )
		y[ i + 1 ] = Add( y[ i ] , Sub( Sk[ 2 * i + 1 ] , Sk[ i + 1 ] ) );
	printf("%d\n", Mul( Div( 2 , n ) , Lagrange( y , n ) ) );
	return 0; 
}
posted @ 2021-04-08 20:48  chihik  阅读(37)  评论(0编辑  收藏  举报