zoukankan      html  css  js  c++  java
  • bzoj3456

    分治+ntt

    设dp[i]表示i个点的图联通的方案数

    那么考虑dp,利用容斥,总-不符合,枚举j=1->i-1,然后考虑不符合,那么考虑和1联通的连通块,剩下的不和1连通,那么dp[i]=2^t(i)-∑j=1->i-1 dp[j]*C(i-1,j-1)*2^t(i-j)

    就是t(i)表示i个点的图的边的个数,那么相当于在j个点的连通图又添加了i-j个点,计算从i-1选出j-1个方案数,这是组合数,然后剩下的不能喝这j个点连,那么自己内部随便连,就是这个式子

    但是这是n^2的,我们化简式子变成卷积,dp[j]*C(i-1,j-1)*2^t(i-j)

    dp[j]*(i-1)!/(j-1)!/(i-j)!*2^t(i-j)

    (dp[j]/(j-1)!)*2^t(i-j)/(i-j)

    这是卷积,但是由于dp[i]和dp[j]有关,那么用cdq优化。

    这是第二次写,还是搞不太清楚下标问题,其实就是构造多项式的时候每个式子个往前移了多少,那么最后统计的时候也往后移动多少

    完全不卡常啊

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 260005, P = 1004535809;
    int n, m, k;
    ll h[N], a[N], b[N], inv[N], facinv[N], fac[N], dp[N], t[N];
    ll power(ll x, ll t)
    {
        ll ret = 1;
        for(; t; t >>= 1, x = x * x % P) if(t & 1) ret = ret * x % P;
        return ret;
    }
    void ntt(ll *a, int f) 
    {
        for(int i = 0; i < n; ++i) 
        {
            int t = 0;
            for(int j = 0; j < k; ++j) if(i >> j & 1) t |= 1 << (k - j - 1);
            if(i < t) swap(a[i], a[t]);
        }
        for(int l = 2; l <= n; l <<= 1) 
        {
            ll w = power(3, f == 1 ? (P - 1) / l : (P - 1) - (P - 1) / l);
            int m = l >> 1;
            for(int i = 0; i < n; i += l) 
            {
                ll t = 1;
                for(int k = 0; k < m; ++k, t = t * w % P) 
                {
                    ll x = a[i + k], y = a[i + k + m] * t % P;
                    a[i + k] = (x + y) % P;
                    a[i + k + m] = ((x - y) % P + P) % P;
                }
            }
        }
        if(f == -1) 
        {
            ll inv = power(n, P - 2);
            for(int i = 0; i < n; ++i) a[i] = a[i] * inv % P;
        }
    }
    void cdq(int l, int r)
    {
        if(l == r) return;
        int mid = (l + r) >> 1;
        cdq(l, mid);
        n = 1;
        k = 0;
        while(n <= r - l + 1) n <<= 1, ++k;
        for(int i = 0; i < n; ++i) a[i] = b[i] = 0;
        for(int i = l; i <= mid; ++i) a[i - l] = dp[i] * facinv[i - 1] % P;
        for(int i = 1; i <= r - l; ++i) b[i] = h[i] * facinv[i] % P;
        ntt(a, 1);
        ntt(b, 1);
        for(int i = 0; i < n; ++i) a[i] = a[i] * b[i] % P;
        ntt(a, -1);
        for(int i = mid + 1; i <= r; ++i) dp[i] = ((dp[i] - a[i - l] * fac[i - 1] % P) % P + P) % P;
        cdq(mid + 1, r);
    }
    int main()
    {
        scanf("%d", &m);
        fac[0] = facinv[0] = 1;
        inv[0] = inv[1] = 1;
        for(int i = 1; i <= m; ++i) 
        {
            if(i != 1) inv[i] = (P - P / i) * inv[P % i] % P;
            fac[i] = fac[i - 1] * i % P;
            facinv[i] = facinv[i - 1] * inv[i] % P;
            t[i] = (ll)i * (i - 1) >> 1;
            dp[i] = h[i] = power(2, t[i]);
        }
        cdq(1, m);
        printf("%lld
    ", dp[m]);
        return 0;
    }
    View Code
  • 相关阅读:
    2019-2020-1 20199310《Linux内核原理与分析》第九周作业
    2019-2020-1 20199310《Linux内核原理与分析》第八周作业
    Android开发笔记(十七)——Fragment详解
    Android开发笔记(十六)——Activity的4种启动模式
    Android开发笔记(十五)——Activity的跳转和数据传递
    Android开发笔记(十四)——Activity的生命周期
    Android开发笔记(十三)——Activity的创建三部曲
    Android实战开发——News
    Android开发笔记(十二)——WebView
    Android开发笔记(十一)——ScrollView滚动视图
  • 原文地址:https://www.cnblogs.com/19992147orz/p/8047136.html
Copyright © 2011-2022 走看看