zoukankan      html  css  js  c++  java
  • hdu5530

    分治ntt

    考虑从添加i,放在j位置,那么1->j是一个连通块,j+1->i和1->j不连通,那么我们可以列出式子dp[i]=∑j=1->i dp[i-j]*A(i-1,j-1)*j^2

    dp[i]表示i个数的答案

    然后化简一下就可以分治ntt了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 3e5 + 5, P = 998244353;
    int n, k;
    ll a[N], b[N], fac[N], inv[N], facinv[N], dp[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 = t * a[i + m + k];
                    a[i + k] = (x + y) % P;
                    a[i + m + k] = ((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] % P;
        for(int i = 1; i <= r - l; ++i) b[i] = (ll)i * 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;
        cdq(mid + 1, r); 
    }
    int main()
    {
        inv[0] = inv[1] = facinv[0] = fac[0] = 1;
        for(int i = 1; i < N; ++i)
        {
            if(i != 1) inv[i] = (P - P / i) * inv[P % i] % P;
            facinv[i] = facinv[i - 1] * inv[i] % P;
            fac[i] = fac[i - 1] * i % P;
        }
        dp[0] = 1;
        cdq(0, 100000); 
        while(scanf("%d", &n) != EOF)
        {
            
            printf("%lld
    ", dp[n]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Git:常用命令记录
    JS笔记(二):隐式转换
    vertical-align/line-height:水平垂直居中
    JS笔记(一):声明提升
    Array.prototype.sort():从一道面试题说起
    CSS笔记(一):选择器规范
    FreeCodeCamp:Profile Lookup
    tile_images_offset的简单使用
    vs2013快捷键等(转)
    Qt状态栏的使用(转)
  • 原文地址:https://www.cnblogs.com/19992147orz/p/8051484.html
Copyright © 2011-2022 走看看