首页 > 其他分享 >「解题报告」ARC140F ABS Permutation (Count ver.)

「解题报告」ARC140F ABS Permutation (Count ver.)

时间:2023-01-27 08:44:18浏览次数:34  
标签:Count ver int len 1ll ABS limit ans Polynomial

洛谷题解说这题是“巨大蠢题。这是我见过的最垃圾的 ARC,没有之一。”

好吧,我不会做巨大蠢题。

首先我们可以想到,如果 \(|a_i - a_j| = m\),那么 \(a_i\) 和 \(a_j\) 一定在关于 \(m\) 的同一剩余系下。所以我们可以将这 \(n\) 个数分成若干个剩余系进行考虑。而我们发现,这相当于将每个剩余系的一些数划分成若干条链,然后链的总长度就是 \(|a_i - a_j| = m\) 的个数。

但是我们发现,划分成的两个链之间也有可能存在 \(|a_i - a_j| = m\),那么以上其实求的是至少,那么二项式反演一下即可。

如何求将 \(n\) 个数划分成 \(k\) 条链,且每个长度 \(\ge 2\) 的链使方案数 \(\times 2\),这样所有划分的总方案数呢?不会组合意义就生成函数,\(F(x)=x+2x^2+2x^3+2x^4+\cdots = \frac{2x}{1 - x} - x\),求 \([x^n] F(x)^k\),大力展开系数可得到:

\[f_k=\sum_{i=0}^k \binom{k}{i}(-1)^i\binom{n-i-1}{k-i-1} 2^{k - i} \]

这东西 NTT 算就行。

每个剩余系直接 EGF 乘起来合并。

然后二项式反演回去即可。

我没想到咋算划分方案数。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2000005;
const int P = 998244353, G = 3;
int qpow(int a, int b) {
    int ans = 1;
    while (b) {
        if (b & 1) ans = 1ll * ans * a % P;
        a = 1ll * a * a % P;
        b >>= 1;
    }
    return ans;
}
const int GI = qpow(G, P - 2);
int r[MAXN];
struct Polynomial {
    vector<int> a;
    int len;
    Polynomial(int len = 0) : len(len) { a.resize(len + 1); }
    void set(int len) { this->len = len; a.resize(len + 1); }
    int& operator[](int b) { return a[b]; }
    void ntt(int limit, bool rev) {
        set(limit);
        for (int i = 0; i < limit; i++) 
            if (i < r[i]) swap(a[i], a[r[i]]);
        for (int mid = 1; mid < limit; mid <<= 1) {
            int step = qpow(rev ? GI : G, (P - 1) / (mid << 1));
            for (int l = 0; l < limit; l += (mid << 1)) {
                int w = 1;
                for (int i = 0; i < mid; i++, w = 1ll * w * step % P) {
                    int x = a[l + i], y = 1ll * w * a[l + i + mid] % P;
                    a[l + i] = (x + y) % P, a[l + i + mid] = (x - y + P) % P;
                }
            }
        }
        if (rev) {
            int inv = qpow(limit, P - 2);
            for (int i = 0; i < limit; i++)
                a[i] = 1ll * a[i] * inv % P;
        }
    }
    Polynomial operator*(Polynomial b) {
        Polynomial a = *this, c;
        int len = a.len + b.len;
        int limit = 1;
        while (limit <= len) limit <<= 1;
        for (int i = 1; i < limit; i++)
            r[i] = (r[i >> 1] >> 1) | ((i & 1) * limit >> 1);
        a.ntt(limit, 0), b.ntt(limit, 0);
        c.set(limit);
        for (int i = 0; i < limit; i++) 
            c[i] = 1ll * a[i] * b[i] % P;
        c.ntt(limit, 1);
        c.set(len);
        return c;
    }
    Polynomial operator^(int b) {
        Polynomial a = *this, ans;
        ans[0] = 1;
        while (b) {
            if (b & 1) ans = ans * a;
            a = a * a;
            b >>= 1;
        }
        return ans;
    }
    void print() {
        for (int i : a)
            printf("%d ", i);
        printf("\n");
    }
};
int n, m;
int fac[MAXN], inv[MAXN];
Polynomial calc(int n) {
    Polynomial f(n), g(n);
    for (int i = 0; i < n; i++) {
        f[i] = 1ll * inv[i] * ((i & 1) ? P - 1 : 1) % P * fac[n - i - 1] % P * qpow((P + 1) / 2, i) % P;
    }
    for (int i = 1; i <= n; i++) {
        g[i] = 1ll * inv[i] * inv[i - 1] % P;
    }
    f = f * g;
    f.set(n);
    for (int i = 0; i <= n; i++) {
        f[i] = 1ll * f[i] * qpow(2, i) % P * fac[i] % P * inv[n - i] % P;
    }
    f[n] = 1;
    return f;
}
int main() {
    scanf("%d%d", &n, &m);
    fac[0] = 1;
    for (int i = 1; i <= n; i++) {
        fac[i] = 1ll * fac[i - 1] * i % P;
    }
    inv[n] = qpow(fac[n], P - 2);
    for (int i = n; i >= 1; i--) {
        inv[i - 1] = 1ll * inv[i] * i % P;
    }
    int q = n % m;
    Polynomial ans = (calc(n / m + 1) ^ q) * (calc(n / m) ^ (m - q));
    for (int i = 0; i <= n; i++) {
        ans[i] = 1ll * ans[i] * fac[i] % P;
    }
    Polynomial f(ans.len), g(ans.len);
    for (int i = 0; i <= n; i++) {
        f[i] = 1ll * ans[n - i] * fac[i] % P;
        g[i] = 1ll * inv[n - i] * (((n - i) & 1) ? P - 1 : 1) % P;
    }
    f = f * g;
    for (int i = 0; i < n; i++) {
        printf("%lld ", 1ll * f[n + i] * inv[i] % P);
    }
    return 0;
}

标签:Count,ver,int,len,1ll,ABS,limit,ans,Polynomial
From: https://www.cnblogs.com/apjifengc/p/17068537.html

相关文章

  • ASP.NET Core+Element+SQL Server开发校园图书管理系统(二)
    随着技术的进步,跨平台开发已经成为了标配,在此大背景下,ASP.NETCore也应运而生。本文主要基于ASP.NETCore+Element+SqlServer开发一个校园图书管理系统为例,简述基于MVC三......
  • 监控Recovery Service Vault备份状态
    接下来再来说下如何监控备份作业的状态,备份不是摆在那就可以的,我们要清楚知道备份是否在成功运行,这就需要监控了,首先来看看如何做RecoveryServiceVault虚机备份的监控主要......
  • SQL Server 2005-2008 ROW_NUMBER() 分页函数效率
    --测试数据量:2161852条declare@idatetimeset@i=GETDATE();--SQL2005-2008--开始WITHtempAS(SELECTid,title,body,ROW_NUMBER()OVER(ORDERBYid)AS'Row......
  • 人脸识别在Serverless架构下的应用
    人脸识别技术介绍早在1965年就有学者对人脸识别技术进行研究,并发表了相关的文章。但是由于计算机计算能力欠缺、人脸数据稀少等,人脸识别技术的研究没有很大的突破,也很少应......
  • 模型升级在Serverless架构下的实现与应用
    1模型升级迭代需求背景介绍众所周知,在人工智能领域,一些训练好的模型会随着时间推移不断优化,数据集也在不断迭代。例如某公司的人脸识别系统因为新员工的入职,老员工的离......
  • 文本情感分析在Serverless架构下的应用
    文本情感分析是指对包含人们观点、喜好、情感等的主观性文本进行检测。该领域的发展和快速起步得益于社交媒体。越来越多的用户从单纯地获取互联网信息向创造互联网信息转......
  • PaddlePaddle与Serverless架构结合
    PaddlePaddle介绍PaddlePaddle(飞桨)以百度多年的深度学习技术研究和业务应用为基础,是中国首个自主研发、功能完备、开源的产业级深度学习平台,集深度学习核心训练和推理框架......
  • PyTorch与Serverless架构结合
    PyTorch介绍2017年1月,FAIR(FacebookAIResearch)发布了PyTorch。其标志如下所示。PyTorch是在Torch基础上用Python语言重新打造的一款深度学习框架,Torch是用Lua语言打造的......
  • TensorFlow与Serverless架构结合
    4.2.1TensorFlow介绍TensorFlow是一个基于数据流编程(DataFlowProgramming)的符号数学系统,被广泛应用于各类机器学习算法的编程实现。其前身是谷歌的神经网络算法库Dist......
  • scikit-learn与Serverless架构结合
    1scikit-learn介绍scikit-learn是一个面向Python的第三方提供的非常强力的机器学习库,简称sklearn,标志如下所示。它建立在NumPy、SciPy和Matplotlib上,包含从数据预处理到......