BZOJ 3456 Urban Planning (combinations count, DP, FFT)

Topic links: https://www.lydsy.com/JudgeOnline/problem.php?id=3456

The famous polynomial exercises, practice a lot, and finally cut off Memorial

Evaluated first wave recursive formula: Order \ (F (n) \) is \ (n-\) points with a reference number of the connected undirected graph, consider complementary set into communication with a numeral not undirected graph number, then enumeration \ (1 \) dots where the block size Unicom: \ [F. (n-) = 2 ^ {n-\ the Choose 2} - \ SUM ^ {n-1} _ {I-1} = { n-1 \ choose i-1
} F (i) 2 ^ {ni \ choose 2} \] this can be done \ (O (^ n-2) \) , in relation to the back bigwigs recount, I here tidy four approaches:

A practice

NTT partition directly optimized, time complexity \ (O (n-\ log ^ 2N) \) . But I will not divide and conquer NTT, so I do not specifically say.

Practice two

\[F(n)=2^{n\choose 2}-\sum^{n-1}_{i=1}\frac{(n-1)!}{(i-1)!(n-i)!}F(i)2^{n-i\choose 2}\\ \frac{F(n)}{(n-1)!}=\frac{2^{n\choose 2}}{(n-1)!}-\sum^{n-1}_{i=1} \frac{F(i)}{(i-1)!}\frac{2^{n-i\choose 2}}{(n-i)!}\]移项可得\[\frac{2^{n\choose 2}}{(n-1)!}=\sum^{n}_{i=1} \frac{F(i)}{(i-1)!}\frac{2^{n-i\choose 2}}{(n-i)!}\]
\(A(x)=\sum_{n>0}\frac{F(n)}{(n-1)!}, G(x)=\sum_{n\ge 0}\frac{2^{n\choose 2}}{n!}, H(x)=\sum_{n>0}\frac{2^{n\choose 2}}{(n-1)!}\), 则有\[F(x)G(x)=H(x)\\ F(x)=H(x)G(x)^{-1}\]
多项式求逆即可。

Time complexity \ (O (n-\ log n-) \) .

This should be the code complexity and operational efficiency best kind of practice, practice and practice three but four also have some instructive.

Practice three

Set \ (G (n) = 2 ^ {n \ choose 2} \) represents \ (n-\) points with a reference number undirected graph. Set \ (F (x), G (x) \) are \ (F (n), G (n) \) exponential generating function (EGF).
Between each other because a plurality of undirected graph by the reference numeral no procedure Unicom blocks, so the exponent generating function \ (G (x) = \ sum_ {n-\ GE. 1} \ FRAC {F. (X) ^ n-} {n-!} \) .
that \ (G (x ) = {E ^ F. (X)} \) , \ (F. (X) = \ G LN (X) \) . polynomials \ (\ LN \) can.

Time complexity \ (O (n-\ log n-) \) .

Practice four

(This practice is my own thinking, wrong please point out) (In fact, this approach is another way to derive practice three)
thanks _rqy uncle of the blog generation Functions Introduction.
Modeled EGF Method Numbers by Bell, the following is derived: {! N-} {! N-} \ [\ FRAC {F. (N-)} = \ FRAC {G (n-)} - \ SUM ^ {n--. 1} _ { i = 1} \ frac {F (i)} {n (i-1)!} \ frac {G (ni)} {(ni)!} \\ \ frac {G (n)} {n!} = \ frac {F (n)} {n!} + \ frac {1} {n} \ sum ^ {n-1} _ {i = 1} \ frac {iF (i)} {i!} \ frac { G (ni)} {(ni
)!} \] here we find \ (\ frac {iF (i )} {i!} \) is \ ([x ^ {i- 1}] F '(x) \ ) , then the equation can be rewritten as \ [[x ^ n] G (x) = [x ^ n] F (x) + \ frac {1} {n} \ sum ^ {n-1} _ {i = 1} [x ^ {i- 1}] F '(x) \ times [x ^ {ni}] G (x) \\ = \ frac {1} {n} (n [x ^ n] F (x ) + \ sum ^ {n- 1} _ {i = 1} [x ^ {i-1}] F '(x) \ times [x ^ {ni}] G (x)) \\ = \ frac { 1} {n} \ sum ^ {n} _ {i = 1} [x ^ {i-1}] F '(x) \ times [x ^ {ni}] G (x) \\ G (x) = \ int ^ x_0 F '( x) G (x) \ text {d} x \\ \ frac {G' (x)} {G (x)} = F '(x) \\ \ ln G (x ) = F. (X) \] .

Must pay attention to summing boundary! I did not pay attention when pushed formula summing the upper bound is \ (n \) or \ ((n-1) \ ) questions the result has been launched to \ (G (x) = F ( x) + \ int ^ x_0 F '(x) G (x) \ text {d} x \) checked one hour ......

Code

Practice two

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iostream>
#define llong long long
using namespace std;

inline int read()
{
    int x=0; bool f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
    if(f) return x;
    return -x;
}

const int N = 1<<19;
const int LGN = 19;
const int P = 1004535809;
const int G = 3;
llong fact[N+3],finv[N+3];

llong quickpow(llong x,llong y)
{
    llong cur = x,ret = 1ll;
    for(int i=0; y; i++)
    {
        if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}
        cur = cur*cur%P;
    }
    return ret;
}
llong mulinv(llong x) {quickpow(x,P-2);}

namespace Polynomial
{
    llong tmp1[N+3],tmp2[N+3],tmp3[N+3],tmp4[N+3],tmp5[N+3],tmp6[N+3];
    int fftid[N+3];
    int getdgr(int n)
    {
        int ret = 1; while(ret<=n) ret<<=1;
        return ret;
    }
    void init_fftid(int dgr)
    {
        int len = 0; for(int i=1; i<=LGN; i++) {if((1<<i)==dgr) {len = i; break;}}
        for(int i=1; i<dgr; i++) fftid[i] = (fftid[i>>1]>>1)|((i&1)<<(len-1));
    }
    void ntt(int dgr,int coe,llong poly[],llong ret[])
    {
        init_fftid(dgr);
        if(poly==ret) {for(int i=0; i<dgr; i++) {if(i<fftid[i]) swap(ret[i],ret[fftid[i]]);}}
        else {for(int i=0; i<dgr; i++) ret[i] = poly[fftid[i]];}
        for(int i=1; i<=(dgr>>1); i<<=1)
        {
            llong tmp = quickpow(G,(P-1)/(i<<1));
            if(coe==-1) tmp = mulinv(tmp);
            for(int j=0; j<dgr; j+=(i<<1))
            {
                llong expn = 1ll;
                for(int k=0; k<i; k++)
                {
                    llong x = ret[j+k],y = ret[i+j+k]*expn%P;
                    ret[j+k] = (x+y)%P;
                    ret[j+i+k] = (x-y+P)%P;
                    expn = expn*tmp%P;
                }
            }
        }
        if(coe==-1)
        {
            llong tmp = mulinv(dgr);
            for(int i=0; i<dgr; i++) ret[i] = ret[i]*tmp%P;
        }
    }
    void polymul(int dgr,llong poly1[],llong poly2[],llong ret[])
    {
        ntt(dgr<<1,1,poly1,tmp1); ntt(dgr<<1,1,poly2,tmp2);
        for(int i=0; i<(dgr<<1); i++) tmp2[i] = tmp1[i]*tmp2[i]%P;
        ntt(dgr<<1,-1,tmp2,ret);
    }
    void polyinv(int dgr,llong poly[],llong ret[])
    {
        for(int i=0; i<dgr; i++) ret[i] = tmp1[i] = 0ll;
        ret[0] = mulinv(poly[0]); tmp1[0] = poly[0];
        for(int i=1; i<=(dgr>>1); i<<=1)
        {
            for(int j=i; j<(i<<1); j++) tmp1[j] = poly[j];
            ntt((i<<2),1,ret,tmp2); ntt((i<<2),1,tmp1,tmp3);
            for(int j=0; j<(i<<2); j++) tmp2[j] = tmp2[j]*tmp2[j]%P*tmp3[j]%P;
            ntt((i<<2),-1,tmp2,tmp3);
            for(int j=0; j<(i<<1); j++) ret[j] = (2ll*ret[j]-tmp3[j]+P)%P;
        }
    }
}
llong f[N+3],g[N+3],h[N+3],ginv[N+3];
int n;

int main()
{
    fact[0] = 1ll; for(int i=1; i<=N; i++) fact[i] = fact[i-1]*i%P;
    finv[N] = quickpow(fact[N],P-2); for(int i=N-1; i>=0; i--) finv[i] = finv[i+1]*(i+1)%P;
    scanf("%d",&n); int dgr = Polynomial::getdgr(n);
    for(int i=0; i<=n; i++) {g[i] = quickpow(2ll,i*(i-1ll)/2ll)*finv[i]%P;}
    for(int i=1; i<=n; i++) {h[i] = quickpow(2ll,i*(i-1ll)/2ll)*finv[i-1]%P;}
//  printf("g: "); for(int i=0; i<dgr; i++) printf("%lld ",g[i]); puts("");
//  printf("h: "); for(int i=0; i<dgr; i++) printf("%lld ",h[i]); puts("");
    Polynomial::polyinv(dgr,g,ginv);
//  printf("ginv: "); for(int i=0; i<dgr; i++) printf("%lld ",ginv[i]); puts("");
    Polynomial::polymul(dgr,ginv,h,f);
    printf("%lld\n",f[n]*fact[n-1]%P);
    return 0;
}

Guess you like

Origin www.cnblogs.com/suncongbo/p/11244604.html