题目
点这里看题目。
题目简述:
给定(k,a,n,d),满足(kle 123, a,n,dle 123456789),求:
[sum_{t=0}^nsum_{j=1}^{a+td}sum_{i=1}^ji^k
]
答案对(1234567891)(不用看了,是个质数)取模。
分析
一个神奇的......插值套插值套插值的题目。
首先,发现(f(n))可以直接插值求出来,是关于(n)的(k+1)次多项式。
然后,差分一下(g),发现(g(n))也可以直接插值求出来,是关于(n)的(k+2)次多项式。
最后,差分一下(h),发现(h(n))还可以直接插值求出来,是关于(n)的(k+3)次多项式。((h(n)-h(n-1)=g(a+nd)),(g)是(k+2)次的)
然后,用(O(k^2))的时间处理(h)的前(k+4)个点的值,再用(O(k))时间插值就好。
数据好像有问题,dark上面有一组数据超过范围了
代码
#include<cstdio>
typedef long long LL;
#define int LL
const int mod = 1234567891;
const int MAXK = 205;
template<typename _T>
void read( _T &x )
{
x = 0;char s = getchar();int f = 1;
while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
while( s >= '0' && 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 ) + 1; }
if( 9 < x ){ write( x / 10 ); }
putchar( x % 10 + '0' );
}
LL pk[MAXK], S[MAXK], SPre[MAXK], H[MAXK];
LL K, A, N, D;
LL qkpow( LL base, LL indx )
{
LL ret = 1;
while( indx )
{
if( indx & 1 ) ret = ret * base % mod;
base = base * base % mod, indx >>= 1;
}
return ret;
}
LL ID( const LL i ) { return A + D * i; }
LL inv( const LL a ) { return qkpow( a % mod, mod - 2 ); }
LL fix( const LL a ) { return ( a % mod + mod ) % mod; }
void add( LL &x, const LL v ) { x = ( x + v >= mod ? x + v - mod : x + v ); }
LL Lagrange( LL n, const LL M, LL *B )
{
if( n <= M ) return B[n]; n %= mod;
LL ans = 0, w = 1, L = 1;
for( int i = 1 ; i <= M ; i ++ ) L = L * ( n - i ) % mod;
for( int i = 2 ; i <= M ; i ++ ) w = w * inv( fix( 1 - i ) ) % mod;
for( int i = 1 ; i <= M ; i ++ )
{
add( ans, L * w % mod * inv( n - i ) % mod * B[i] % mod );
if( i < M ) w = w * fix( i - M ) % mod * inv( i ) % mod;
}
return ans;
}
LL f( const LL n ) { return Lagrange( n, K + 2, S ); } //k+1
LL g( const LL n ) { return Lagrange( n, K + 3, SPre ); } //k+2
LL h( const LL n ) { return Lagrange( n, K + 4, H ); } //k+3
void init()
{
for( int i = 1 ; i <= K + 5 ; i ++ ) pk[i] = qkpow( i, K );
for( int i = 1 ; i <= K + 5 ; i ++ ) S[i] = ( S[i - 1] + pk[i] ) % mod;
for( int i = 1 ; i <= K + 5 ; i ++ ) SPre[i] = ( SPre[i - 1] + S[i] ) % mod;
for( int i = 1 ; i <= K + 5 ; i ++ ) H[i] = ( H[i - 1] + g( ID( i - 1 ) ) ) % mod;
}
signed main()
{
int T;
read( T );
while( T -- )
{
read( K ), read( A ), read( N ), read( D );
init();
write( h( N + 1 ) ), putchar( '
' );
}
return 0;
}