[jzoj3303]【集训队互测2013】城市规划

版权声明:本文为博主原创文章,转载时请标明出处。 https://blog.csdn.net/FarmerJohnOfZS/article/details/80881822

【集训队互测2013】城市规划

Solution

f i 为点数为 i 时的答案, g i 为此时所有图个数,则 g i = 2 C n 2

不难得到 f n = g n i = 1 n 1 f i g i C n 1 i 1

把相关项处理一下就有

2 C n 2 ( n 1 ) ! = k = 1 n f k ( k 1 ) ! 2 C n k 2 ( n k ) !

注意到只有一部分是未知的 利用多项式求逆把 f i 放到左边即可

其实还可以用CDQ分治解决 哪天写完了再放上来

Mistakes

才不是因为错误太多了单列一栏

  1. 指数对(Mo-1)取模 但指数的指数不能再运用费马小定理
  2. 多项式求逆中,次数界是变化的,所以要重新预处理
  3. 注意运算中每个多项式应保持次数界一致(补零)
  4. 时时检查运算溢出!

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#define oo 2139062143
#define fo(i,x,y) for (ll i=(x);i<=(y);++i)
#define fd(i,x,y) for (ll i=(x);i>=(y);--i)
using namespace std;
typedef long long ll;
const ll N=8*(262144+10)/*2^18*/,mo=1004535809/*g=3*/;
ll n,M;
ll W[N],h[N],g[N],wz[N];
ll re[N],jc[N];
ll qsm(ll x,ll y)
{
    y%=(mo-1);
    ll rt=1;
    fo(i,0,30)
    {
        if((1<<i)&y) rt=1ll*rt*x%mo;
        x=1ll*x*x%mo;
    }
    return rt;
}
void init(ll x)
{
    for(M=1;M<x;M<<=1);
    W[0]=1,W[1]=qsm(3,(mo-1)/M);fo(i,2,M) W[i]=1ll*W[i-1]*W[1]%mo;
    wz[0]=0;fo(i,1,M) wz[i]=(wz[i>>1]>>1)+((i&1)*(M>>1));
}
ll a[N];
void dft(ll *c)
{
    fo(i,0,M-1) a[wz[i]]=c[i];ll tp;
    for(ll wv=2,hf=1;wv<=M;hf=wv,wv<<=1)
    fo(i,0,hf-1) for (ll l=i;l<M;l+=wv)
    tp=1ll*W[1ll*M/wv*i]*a[l+hf]%mo,a[l+hf]=(a[l]-tp+mo)%mo,a[l]=(a[l]+tp)%mo;
    fo(i,0,M-1) c[i]=(a[i]+mo)%mo;
}
ll d[N],e[N],f[N];
void opit(ll *c)//Rev[i]=2*rev[i]-a[i]*rev[i]*rev[i];
{
    fo(i,0,M-1) d[i]=c[i],c[i]=0;
    c[0]=qsm(d[0],mo-2);ll gg=M;
    for (ll mp=2;mp<=gg;mp<<=1)
    {
        init(mp*2);
        fo(i,0,M-1) e[i]=c[i];
        dft(e);
        fo(i,0,M-1) e[i]=(e[i]*e[i])%mo;
        fo(i,0,(M>>1)-1)f[i]=d[i];fo(i,M>>1,M-1) f[i]=0;
        dft(f);
        fo(i,0,M-1) f[i]=(f[i]*e[i])%mo;
        fo(i,1,M>>1) swap(W[i],W[M-i]);
        dft(f);ll tp=qsm(M,mo-2);
        fo(i,0,M-1) f[i]=f[i]*tp%mo;
        fo(i,0,(M>>1)-1) c[i]=(2*c[i]-f[i]+mo)%mo;
    }
}
ll C(ll x)
{
    return((1ll*x*(x-1)/2));
}
int main()
{
    scanf("%lld",&n);
    jc[0]=1;fo(i,1,n) jc[i]=(1ll*jc[i-1]*i)%mo;
    re[n]=qsm(jc[n],mo-2);
    fd(i,n-1,0) re[i]=(1ll*re[i+1]*(i+1))%mo;
    fo(i,0,n) 
    {
        if(i)g[i]=1ll*qsm(2,C(i))*re[i-1]%mo;
        h[i]=1ll*qsm(2,C(i))*re[i]%mo;
    }
    init(n*2);
    dft(g);
    opit(h);
    init(n*2);
    dft(h);
    fo(i,0,M-1) h[i]=1ll*h[i]*g[i]%mo; 
    fo(i,1,M>>1) swap(W[i],W[M-i]);
    dft(h);ll tp=qsm(M,mo-2);
    ll p=(h[n]*tp)%mo;
    printf("%lld",(1ll*p*jc[n-1]%mo));
    return 0;
}
















猜你喜欢

转载自blog.csdn.net/FarmerJohnOfZS/article/details/80881822