zoukankan      html  css  js  c++  java
  • 51nod 1514 美妙的序列

    如果一个长度为 $n$ 的排列的任意一个严格前缀都不是一个 $1 sim i$ 的排列,则称这个排列是合法的,$T$ 次求有多少长度为 $n$ 的合法的排列

    $T,n leq 10^5$

    sol:

    小清新多项式题,考虑 dp,$f_i$ 表示长度为 $i$ 的合法排列数量,$g_i$ 表示长度为 $i$ 的所有排列数量,考虑容斥

    一个不合法的排列一定存在至少一个 $x$ 使 $[1,x]$ 是排列,$[x+1,n]$ 是排列

    但因为是“至少一个”没法枚举,但发现我们可以只枚举第一个 $x$ 的位置,后面随便排就好了,因为此时已经不合法

    枚举 $x$ 相当于枚举当前排列中极长的合法前缀长度,有 $g_n = sumlimits_{i=0}^{n-1} f_i imes g_{n-i}$

    然后发现是个多项式求逆的标准形式

    如何求 $g_i$ 呢?很明显,$g_n = n!$

    #include <bits/stdc++.h>
    #define LL long long
    #define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
    #define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
    using namespace std;
    inline int read() {
        int x = 0, f = 1;
        char ch;
        for (ch = getchar(); !isdigit(ch); ch = getchar())
            if (ch == '-')
                f = -f;
        for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
        return x * f;
    }
    const int maxn = 600010, mod = 998244353;
    int F[maxn], G[maxn];
    inline int skr(int x, int t) {
        int res = 1;
        for (; t; x = 1LL * x * x % mod, t >>= 1)
            if (t & 1)
                res = 1LL * res * x % mod;
        return res;
    }
    int r[maxn], lg[maxn], temp[maxn];
    int inv[maxn], ifac[maxn], fac[maxn];
    inline int skr(int x, LL t) {
        int res = 1;
        while (t) {
            if (t & 1)
                res = 1LL * res * x % mod;
            x = 1LL * x * x % mod;
            t = t >> 1;
        }
        return res;
    }
    inline void fft(int *a, int n, int type) {
        for (int i = 0; i < n; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lg[n] - 1));
        for (int i = 0; i < n; i++)
            if (i < r[i])
                swap(a[i], a[r[i]]);
        for (int i = 1; i < n; i <<= 1) {
            int wn = skr(3, (mod - 1) / (i << 1));
            if (type == -1)
                wn = skr(wn, mod - 2);
            // cout << wn << endl;
            for (int j = 0; j < n; j += (i << 1)) {
                int w = 1;
                for (int k = 0; k < i; k++, w = (1LL * (LL)w * (LL)wn) % mod) {
                    int x = a[j + k], y = (1LL * (LL)w * (LL)a[j + k + i]) % mod;
                    a[j + k] = (x + y) % mod;
                    a[j + k + i] = (((x - y) % mod) + mod) % mod;
                }
            }
        }
        if (type == -1) {
            int inv = skr(n, mod - 2);
            for (int i = 0; i < n; i++) a[i] = ((LL)a[i] * (LL)inv) % mod;
        }
    }
    inline void Inverse(int *a, int *b, int n) {
        if (n == 1) {
            b[0] = skr(a[0], mod - 2);
            return;
        }
        Inverse(a, b, n >> 1);
        memcpy(temp, a, n * sizeof(int));
        memset(temp + n, 0, n * sizeof(int));
        fft(temp, n << 1, 1);
        fft(b, n << 1, 1);
        for (int i = 0; i < (n << 1); i++)
            b[i] = 1LL * b[i] * ((2LL - 1LL * temp[i] * b[i] % mod + mod) % mod) % mod;
        fft(b, n << 1, -1);
        memset(b + n, 0, n * sizeof(int));
    }
    int c[maxn], d[maxn];
    inline void Ln(int *a, int *b, int n) {
        Inverse(a, c, n);
        for (int i = 0; i < n - 1; ++i) d[i] = (LL)(i + 1) * a[i + 1] % mod;
        d[n - 1] = 0;
        fft(c, n << 1, 1);
        fft(d, n << 1, 1);
        for (int i = 0; i < (n << 1); ++i) c[i] = 1LL * d[i] * c[i] % mod;
        fft(c, (n << 1), -1);
        for (int i = 1; i < (n << 1); ++i) b[i] = 1LL * inv[i] * c[i - 1] % mod;
        b[0] = 0;
        for (int i = 0; i < (n << 1); ++i) c[i] = d[i] = 0;
    }
    int temp_w[maxn], temp_Ln[maxn];
    inline void Exp(int *a, int *b, int n) {
        if (n == 1) {
            b[0] = 1;
            return;
        }
        Exp(a, b, n >> 1);
        memcpy(temp_w, b, sizeof(int) * n);
        memset(temp_w + n, 0, sizeof(int) * n);
        Ln(b, temp_Ln, n);
        for (int i = 0; i < n; i++) temp_Ln[i] = (mod + a[i] - temp_Ln[i]) % mod;
        (temp_Ln[0] += 1) %= mod;
        fft(temp_w, n << 1, 1);
        fft(temp_Ln, n << 1, 1);
        for (int i = 0; i < (n << 1); i++) temp_w[i] = 1LL * temp_w[i] * temp_Ln[i] % mod;
        fft(temp_w, n << 1, -1);
        memcpy(b, temp_w, n * sizeof(int));
        memset(b + n, 0, n * sizeof(int));
        memset(temp_w, 0, sizeof(int) * (n << 1));
        memset(temp_Ln, 0, sizeof(int) * (n << 1));
    }
    int main() {
        lg[0] = -1;
        rep(i, 1, 600000) lg[i] = lg[i >> 1] + 1;
        inv[1] = ifac[0] = fac[0] = 1;
        rep(i, 1, 600000) {
            if (i != 1) inv[i] = -(LL)mod / i * inv[mod % i] % mod;
            inv[i] = ((inv[i] % mod) + mod) % mod;
            ifac[i] = (LL)ifac[i - 1] * inv[i] % mod;
            fac[i] = (LL)fac[i - 1] * i % mod;
        }
        int len = 1; for(; len <= 200000; len <<= 1);
        memcpy(F, fac, sizeof(F)); Inverse(F, G, len);
        rep(i, 0, len-1) G[i] = mod - G[i]; G[0]++;
        int T = read();
        while(T--) cout << G[read()] << '
    ';
    }
    View Code
  • 相关阅读:
    触发Full GC执行的情况 以及其它补充信息
    HotSpot垃圾收集器GC的种类
    JVM学习之GC常用算法
    十大经典排序算法
    Java transient关键字使用
    Java并发编程:volatile关键字解析
    Linux Centos7.2 编译安装PHP7.0.2
    深入理解分布式事务及高并发下分布式事务的解决方案
    Windows及Linux环境搭建Redis集群
    软件项目进度管理(含敏捷项目管理)
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10722381.html
Copyright © 2011-2022 走看看