zoukankan      html  css  js  c++  java
  • luoguP5591 【小猪佩奇学数学】

    由于存在一道题叫做白兔之舞就导致这道题看上去非常的板(......()如果按照这个方法推下来

    约定,([x])表示(x)向下取整

    [sum_{i=0}^ndbinom{n}{i} imes p^i imes [dfrac{i}{k}] ]

    然后会想到可以将([dfrac{i}{k}])拆开变成:

    [dfrac{i-i\%k}{k} ]

    于是原问题变成:

    [sum_{i=0}^ndbinom{n}{i} imes p^i imesdfrac{i-i\%k}{k} ]

    看到了(i\%k),然后还有组合数,然后(k)还是(2)的整数次幂,这个时候当然是单位根反演上场了...

    [sum_{t=0}^{k-1}sum_{i=0}^n[i\%k==t]dbinom{n}{i} imes dfrac{i-t}{k} imes p^i ]

    然后就是喜闻乐见的化式子了

    [sum_{t=0}^{k-1}sum_{i=0}^n[(i-t)\%k==0]dbinom{n}{i} imes dfrac{i-t}{k}p^i ]

    [sum_{t=0}^{k-1}sum_{i=0}^ndfrac{1}{k}sum_{j=0}^{k-1}omega_{k}^{(i-t)j} imesdbinom{n}{i} imesdfrac{i-t}{k}p^i ]

    [dfrac{1}{k^2}sum_{t=0}^{k-1}sum_{i=0}^nsum_{j=0}^{k-1}omega_{k}^{(i-t)j} imesdbinom{n}{i} imes(i-t)p^i ]

    [dfrac{1}{k^2}sum_{t=0}^{k-1}sum_{i=0}^nsum_{j=0}^{k-1}omega_{k}^{ij} imesomega_{k}^{-tj} imesdbinom{n}{i} imes(i-t)p^i ]

    然后肯定要交换求和顺序变成:

    [dfrac{1}{k^2}sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=0}^{n}omega_{k}^{ij} imes dbinom{n}{i} imes (i-t)p^i ]

    然后这里是可以将其拆开的...

    [dfrac{1}{k^2}sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=0}^{n}omega_{k}^{ij} imes dbinom{n}{i} imes i imes p^i-dfrac{1}{k^2}sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=0}^{n}omega_{k}^{ij} imes dbinom{n}{i}*tp^i ]

    我们先忽略(dfrac{1}{k^2})

    [sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=0}^{n}omega_{k}^{ij} imes dbinom{n}{i} imes i imes p^i-sum_{t=0}^{k-1}t imes sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=0}^{n}omega_{k}^{ij} imes dbinom{n}{i}p^i ]

    [sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=0}^{n}(omega_{k}^{j}p)^i imes dbinom{n}{i} imes i-sum_{t=0}^{k-1}t imes sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=0}^{n}(omega_{k}^{j}p)^i imes dbinom{n}{i} ]

    第二个式子很好处理,我们直接用二项式定理即可化开变成:

    [sum_{t=0}^{k-1}t imes sum_{j=0}^{k-1}omega_{k}^{-tj}(omega_{k}^{j}p+1)^n ]

    然后对于某一个(j)((omega_{k}^{j}p+1)^n)为定值,设其为(a_j)

    第一个式子可以将组合数拆开

    [sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=0}^{n}(omega_{k}^{j}p)^i imes dbinom{n}{i} imes i ]

    [sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=0}^{n}(omega_{k}^{j}p)^i imes dfrac{n!}{i!*(n-i)!} imes i ]

    然后这个时候可以将(i=0)的那一项给忽略掉

    [sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=1}^{n}(omega_{k}^{j}p)^i imes dfrac{n!}{(i-1)!(n-i)!} ]

    [sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=1}^{n}(omega_{k}^{j}p)^i imes dfrac{n*(n-1)!}{(i-1)!((n-1)-(i-1))!} ]

    [n*sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=1}^{n}(omega_{k}^{j}p)^{i-1+1} imes dfrac{(n-1)!}{(i-1)!((n-1)-(i-1))!} ]

    [n*sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj}sum_{i=1}^{n}(omega_{k}^{j}p)^{i-1}*omega_{k}^jp imes dfrac{(n-1)!}{(i-1)!((n-1)-(i-1))!} ]

    [n*sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj} imes omega_{k}^jpsum_{i-1=0}^{n-1}(omega_{k}^{j}p)^{i-1} imes dfrac{(n-1)!}{(i-1)!((n-1)-(i-1))!} ]

    [n*sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj} imes omega_{k}^jpsum_{i-1=0}^{n-1}(omega_{k}^{j}p)^{i-1} imes dbinom{n-1}{i-1} ]

    [n*sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj} imes omega_{k}^jpsum_{i=0}^{n-1}(omega_{k}^{j}p)^{i} imes dbinom{n-1}{i} ]

    [n*sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj} imes omega_{k}^jp*(omega_{k}^{j}p+1)^{n-1} ]

    后面那一坨对于某一个(j)也是固定的,我们可以设(b_j=omega_{k}^jp*(omega_{k}^jp+1)^{n-1})

    那么就有原式即:

    [n*sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-tj} imes b_j-sum_{t=0}^{k-1}t*sum_{j=0}^{k-1}omega_{k}^{-tj}a_j ]

    然后我们就得到了一个(O(k^2))的做法了...

    然后我们用一下白兔之舞的神仙操作(tj=dfrac{(t+j)(t+j-1)}{2}-dfrac{j(j-1)}{2}-dfrac{t(t-1)}{2})

    证明也很简单,分子是:

    [(t+j)^2-t-j-j^2+j-t^2+t ]

    [2tj ]

    所以原式就可以化成:

    下面的组合数都反了,但我懒得改了QAQ

    [n*sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-(inom{2}{t+k}-inom{2}{t}-inom{2}{j})} imes b_j-sum_{t=0}^{k-1}t*sum_{j=0}^{k-1}omega_{k}^{-(inom{2}{t+k}-inom{2}{t}-inom{2}{j})}a_j ]

    [n*sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-inom{2}{t+k}+inom{2}{t}+inom{2}{j}} imes b_j-sum_{t=0}^{k-1}t imes sum_{j=0}^{k-1}omega_{k}^{-inom{2}{t+k}+inom{2}{t}+inom{2}{j}}a_j ]

    [n*sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-inom{2}{t+k}} omega_{k}^{inom{2}{t}}omega_k^{inom{2}{j}}*b_j-sum_{t=0}^{k-1}sum_{j=0}^{k-1}omega_{k}^{-inom{2}{t+k}} t imes omega_{k}^{inom{2}{t}}omega_k^{inom{2}{j}}a_j ]

    然后如果我们将(t+k)看作一个整体那么就会发现这是一个卷积的形式

    然后就只需要将(omega_{k}^{inom{2}{t}})(omega_k^{inom{2}{j}} imes b_j)以及(t imes omega_{k}^{inom{2}{t}})(omega_k^{inom{2}{j}} imes a_j)分别卷起来即可,暴力卷是需要( m 6NTT)的...

    还担心会( m T)来着...然而事实上也不慢,开( m O2)最慢的点才(1.3s)..不过其实可以做( m 3FFT)的...因为卷起来可以将结果乘起来再加起来...同时把两个多项式的( m DFT)算出来需要(3)次变(2)次的技巧...所以速度应该会还可以

    复杂度(O(klog k))

    (Code:)

    #include<bits/stdc++.h>
    using namespace std ;
    #define rep( i, s, t ) for( register int i = s; i <= t; ++ i )
    #define re register
    #define LL long long
    #define int long long
    int gi() {
    	char cc = getchar() ; int cn = 0, flus = 1 ;
    	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
    	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
    	return cn * flus ;
    }
    const int Gi = 332748118 ;
    const int P = 998244353 ; 
    const int N = 4e6 + 5 ;  
    const int G = 3 ;
    int n, p, m, limit, L, R[N] ;
    LL A[N], B[N], F[N], F2[N], Dg[N], Inv ;
    LL fpow( LL x, int k ) {
    	LL ans = 1, base = x % P ; k = k % ( P - 1 ) ; 
    	while( k ) {
    		if( k & 1 ) ans = ( ans * base ) % P ; 
    		base = ( base * base ) % P, k >>= 1 ; 
    	}
    	return ans % P ;
    }
    void NTT( LL *a, int type ) {
    	for( re int i = 0; i < limit; ++ i ) if( i < R[i] ) swap( a[i], a[R[i]] ) ;
    	for( re int k = 1; k < limit; k <<= 1 ) {
    		LL dg = fpow( ( type == 1 ) ? G : Gi, ( P - 1 ) / ( k << 1 ) ); 
    		for( re int i = 0; i < limit; i += ( k << 1 ) )
    		for( re LL j = i, g = 1; j < i + k; ++ j, g = ( g * dg ) % P ) {
    			LL Nx = a[j], Ny = ( a[j + k] * g ) % P;
    			a[j] = ( Nx + Ny ) % P, a[j + k] = ( Nx - Ny + P ) % P ; 
    		}
    	}
    	if( type != 1 ) rep( i, 0, limit - 1 ) a[i] = ( a[i] * Inv ) % P ; 
    }
    void Init() {
    	limit = 1, L = 0 ;
    	while( limit < m + m ) limit <<= 1, ++ L ; 
    	for( int i = 0; i < limit; ++ i ) R[i] = ( R[i >> 1] >> 1 ) | ( ( i & 1 ) << ( L - 1 ) ) ;
    	Inv = fpow( limit, P - 2 ) ;
    }
    LL C( int x ) {
    	return 1ll * x * ( x - 1 ) / 2 ; 
    }
    signed main()
    {
    	n = gi(), p = gi(), m = gi() ;  
    	Dg[0] = 1, Dg[1] = fpow( G, ( P - 1 ) / m ) ;
    	rep( i, 2, m ) Dg[i] = ( Dg[i - 1] * Dg[1] ) % P ; 
    	rep( i, 0, m - 1 ) A[i] = fpow( Dg[i] * p + 1, n ), B[i] = Dg[i] * p % P * fpow( Dg[i] * p + 1, n - 1 ) % P ;
    	
    	LL Ans1 = 0, Ans2 = 0, Ans = 0 ;
    	rep( i, 0, m - 1 ) A[i] = Dg[C(i) % m] * A[i] % P, B[i] = Dg[C(i) % m] * B[i] % P, 
    	F[i] = Dg[C(i) % m] % P, F2[i] = 1ll * i * Dg[C(i) % m] % P ;
    	Init(), NTT( A, 1 ), NTT( B, 1 ), NTT( F, 1 ), NTT( F2, 1 ) ; 
    	rep( i, 0, limit - 1 ) A[i] = ( F2[i] * A[i] ) % P, B[i] = ( F[i] * B[i] ) % P ;
    	NTT( A, -1 ), NTT( B, -1 ) ;
    	
    	rep( i, 0, limit ) A[i] = A[i] * Dg[m - C(i) % m] % P, B[i] = B[i] * Dg[m - C(i) % m] % P, 
    		Ans2 = ( Ans2 + A[i] ) % P, Ans1 = ( Ans1 + B[i] ) % P ; 
    	
    	Ans1 = ( 1ll * Ans1 * ( n % P ) ) % P ;  
    	Ans = ( Ans1 - Ans2 + P ) % P ;
    	Ans = ( Ans * fpow( m * m % P, P - 2 ) ) % P ;
    	printf("%lld
    ", Ans ) ;
    	return 0 ;
    }
    

    因为多项式实在是做少了所以调得非常自闭...,下次再写我开数组绝对不这么吝啬QAQ我错了

  • 相关阅读:
    Spring学习之旅(二)--容器
    Spring学习之旅(一)--初始Spring
    Logback的使用
    DES加解密工具类
    Lombok插件的使用
    from 表单用 GET 方法进行 URL 传值时后台无法获取问题
    组播
    linux头文件路径
    IANA
    6号板获取或放文件
  • 原文地址:https://www.cnblogs.com/Soulist/p/11673254.html
Copyright © 2011-2022 走看看