首页 > 其他分享 >没这种事

没这种事

时间:2024-10-21 16:59:55浏览次数:1  
标签:qp 这种 int res ll len 多项式

没这种事

\(n,m\) 中有奇数的情况,可以发现中心的那一列与外面完全无关,直接拎出来数一下答案之后,最后与 \(n,m\) 都是偶数的答案相乘就是原来的答案了。接下来只需要考虑 \(n,m\) 都是偶数的情况。

矩阵的变换显然只会对关于中心对称的四个点施加置换。我们可以玩出这样一个结论:对于这四个点,我们可以在不改变其它位置的情况下施加任意偶置换,所以说,每个组之间的联动性单纯只体现在置换的奇偶性上。

而且如果有一个组中有两个相同的元素,交换这两个元素改变了奇偶性却没改变矩阵,所以说有元素相同的组可以在不扰动其它位置的情况下任意排列。

我们考虑这个限制的形式是一张二分图:如果一个组元素互不相同,则在它最小的行编号与最小的列编号之间连一条边,一个局面能被原局面到达,当且仅当考虑给每条边标上对应置换的奇偶性之后,每一个环的边权和都是偶数。即将其视作异或方程组之后有解。那么一个局面能到达的局面数量只与它连出来的这张图的树边条数或者说连通块数有关。

二分图的连通块数,考虑先求 \(\ln\) 求出联通二分图的 EGF 之后乘上每个连通块的系数 \(\exp\) 回来。本题中系数是 \(\frac{1}{2}\),所以这个过程可以完全简化成开根。

二维 EGF 开根怎么做?考虑 zhy 在 YAMMCP 中教育到的处理二元多项式的常见手段。

即如果我们想对二元 GF 做什么操作,考虑一元 GF \(\operatorname{polylog}\) 做这个操作时所需要的步骤,往往只需要多项式意义下的线性操作,也就是加、数乘和卷积。你当然可以内层封装一个实现多项式域运算操作的 struct,这样的复杂度一般可以做到 \(O(n\operatorname{polylog}(n))\),但是往往过于难写而且常数巨大,尤其是一元 GF 的 \(\exp\) 操作本来常数巨大十分难写难记,我们需要更加亲民的搞法。

有一种好写的、更加高效的想法。考虑二元 GF 较小的一维是根号规模的,所以这一维的部分可以上平方的递推做法,只有常数项一般需要快速做一次一元多项式操作求出来。而内层也千万不要封装了,因为多数平方递推部分每次都 IDFT 回来太亏,我们见招拆招只在需要截断或者需要输出的时候才 IDFT 还原,其它时候的一直保持点值形态更加方便处理,常数极小。复杂度是根号级别的。

如果保证两位都是根号规模的,面对非费马质数的质数模数,我们可以直接使用插值代替 NTT,常数项处的一元多项式操作我们也可以使用平方递推代替。复杂度依然是根号级别的。

有趣的事实:zhy 提到的,将 \(x^B\) 换元成 \(y\),这导出了一个不依赖费马质数的 \(O(n\sqrt n)\) 多项式乘法算法,是不是很快,思路清晰之后这个做法还是非常好写的。

Karatsuba,你是不是彻底没用了。

记得特判二分图不连边的系数是 \(0\) 的情况,否则过不了 uoj 的 hack。

#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int P = 998244353;
const int N = 1 << 20;
inline void inc(int &x, int v) {
    if ((x += v) >= P)
        x -= P;
}
inline void dec(int &x, int v) {
    if ((x -= v) < 0)
        x += P;
}
int qp(int a, int b = P - 2) {
    int res = 1;
    while (b) {
        if (b & 1)
            res = (ll)res * a % P;
        a = (ll)a * a % P;
        b >>= 1;
    }
    return res;
}
int n, m, k;
int calcline(int x) {
    return (2ll * qp(k, 2 * x) - qp(k, x) + P) % P;
}
const int coe[4] = {1, 68, 432, 288};
const int iv[4] = {qp(1), qp(2), qp(3), qp(4)};
int ibn[N], bn[N], pw[N];
int *f[N], g[N];
int len, ilen, bt;
int rev[N], cw[N | 1];
int fac[N], fiv[N];
void init(int _len) { // mod x^len
    len = 1, bt = -1;
    while (len <= _len)
        len <<= 1, ++bt;
    int w = qp(3, (P - 1) >> (bt + 1));
    cw[0] = cw[len] = 1;
    for (int i = 1; i < len; ++i) {
        cw[i] = (ll)cw[i - 1] * w % P;
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bt);
    }
    ilen = qp(len);
}
void NTT(int *F) {
    for (int i = 1; i < len; ++i)
        if (rev[i] < i)
            swap(F[rev[i]], F[i]);
    for (int i = 1, tt = len >> 1; i < len; i <<= 1, tt >>= 1)
        for (int j = 0; j < len; j += (i << 1))
            for (int k = j, t = 0; k < (j | i); ++k, t += tt) {
                int x = F[k], y = (ll)F[k | i] * cw[t] % P;
                if ((F[k] = x + y) >= P)
                    F[k] -= P;
                if ((F[k | i] = x - y) < 0)
                    F[k | i] += P;
            }
}
void INTT(int *F) {
    for (int i = 1; i < len; ++i)
        if (rev[i] < i)
            swap(F[rev[i]], F[i]);
    for (int i = 1, tt = len >> 1; i < len; i <<= 1, tt >>= 1)
        for (int j = 0; j < len; j += (i << 1))
            for (int k = j, t = len; k < (j | i); ++k, t -= tt) {
                int x = F[k], y = (ll)F[k | i] * cw[t] % P;
                if ((F[k] = x + y) >= P)
                    F[k] -= P;
                if ((F[k | i] = x - y) < 0)
                    F[k | i] += P;
            }
    for (int i = 0; i < len; ++i)
        F[i] = (ll)F[i] * ilen % P;
}
int main() {
    scanf("%d%d%d", &n, &m, &k);
    if (n > m)
        swap(n, m);
    int res = 1;
    if (n & 1)
        res = (ll)res * calcline(m >> 1) % P;
    if (m & 1)
        res = (ll)res * calcline(n >> 1) % P;
    if (n & m & 1)
        res = (ll)res * k % P;
    n >>= 1, m >>= 1;
    if (!n or !m) {
        printf("%d\n", res);
        return 0;
    }
    int c0 = 0, c1 = 0;
    for (int i = 0, now = 1; i < 4; ++i) {
        now = (ll)now * (k - i) % P * iv[i] % P;
        if (i < 3)
            inc(c0, (ll)now * coe[i] % P);
        else
            inc(c1, (ll)now * coe[i] % P);
    }
    if (c0)
        c1 = (ll)c1 * qp(c0) % P;
    int sum = 0;
    fac[0] = pw[0] = ibn[0] = bn[0] = 1;
    for (int i = 1; i <= n * m; ++i)
        pw[i] = (ll)pw[i - 1] * (c1 + 1) % P;
    for (int i = 1; i <= m; ++i) {
        fac[i] = (ll)fac[i - 1] * i % P;
        ibn[i] = ibn[i - 1] * 499122176ll % P;
        inc(bn[i] = bn[i - 1], bn[i - 1]);
    }
    fiv[m] = qp(fac[m]);
    for (int i = m; i; --i)
        fiv[i - 1] = (ll)fiv[i] * i % P;
    init(m << 1);
    for (int i = 0; i <= n; ++i)
        f[i] = new int[len]();
    for (int i = 0; i <= m; ++i)
        f[0][i] = 499122177ll * fiv[i] % P * ibn[i] % P;
    NTT(f[0]);
    for (int i = 1; i <= n; ++i) {
        for (int x = 0; x < len; ++x)
            g[x] = 0;
        for (int j = 1; j < i; ++j)
            for (int x = 0; x < len; ++x)
                inc(g[x], (ll)f[j][x] * f[i - j][x] % P);
        INTT(g);
        for (int x = 0; x <= m; ++x)
            dec(f[i][x] = (ll)fiv[i] * fiv[x] % P * pw[i * x] % P, g[x]);
        NTT(f[i]);
        for (int x = 0; x < len; ++x)
            f[i][x] = (ll)f[i][x] * f[0][x] % P;
        INTT(f[i]);
        for (int x = m + 1; x < len; ++x)
            f[i][x] = 0;
        if (i == n) {
            sum = (ll)f[n][m] * fac[n] % P * fac[m] % P;
            break;
        }
        NTT(f[i]);
    }
    if (c0)
        res = (ll)res * qp(c0, n * m) % P * sum % P * bn[n] % P * bn[m] % P;
    else
        res = (ll)res * qp(c1, n * m) % P * bn[n] % P * bn[m - 1] % P;
    printf("%d\n", res);
    return 0;
}

标签:qp,这种,int,res,ll,len,多项式
From: https://www.cnblogs.com/yyyyxh/p/18489727/sonnakotohanai

相关文章

  • 你还在用“有毒”电路板?这种PCB可能是你更好的选择...
    什么是无卤PCB,相比于普通PCB板材有哪些优势与长处,快来一起涨芝士吧!一、什么是无卤PCB无卤PCB是指电路板中所含卤素的含量符合特定限制标准的印刷电路板。国际电化学委员会(IEC)将无卤PCB定义为电路板中总卤素含量不超过。其产生有着多方面的背景。现如今,随着人们的环保意......
  • 这种题都做不出来我还打个集贸的 OI 啊
    不是,这种题没想出来,如此,如何备战CSP。description给定长度为\(n\)的序列\(a\),以及\(m\)个数对\((l_i,r_i)\)。你可以进行下列操作至多一次:选择序列\(a\)的一个子段,并将其中的每个元素的值都改成任意整数。你需要保证执行完操作之后,对于每个整数\(i(1\leqi\leqm......
  • 倾斜摄影切片怎么做?这种切片方式简单方便还免费!
    倾斜摄影是一种从多个角度(通常是垂直、斜45度)拍摄地面或建筑物的影像技术,通过结合这些不同视角的照片,可以生成具有真实感的三维模型。倾斜摄影通常用于城市建模、地形勘测和测绘等领域,能够准确还原建筑物和地形的立体结构。然而,倾斜摄影生成的三维数据体量庞大,直接展示时面临渲染......
  • 在 LaTeX 中,默认的 `enumerate` 环境会输出 “1. 2. 3.“ 这样的编号。如果你想将编号
    在LaTeX中,默认的enumerate环境会输出“1.2.3.”这样的编号。如果你想将编号格式改为(1)(2)(3)这种样式,你可以通过enumerate包进行自定义。在导言区导入enumerate包:\usepackage{enumerate}在enumerate环境中使用\renewcommand来自定义编号格式为带括号的样式......
  • 【异常错误】RuntimeError: CUDA error: device-side assert triggered 遇到这种错误
    遇到的错误:运行的时候突然就这样了 /pytorch/aten/src/ATen/native/cuda/Indexing.cu:699:indexSelectLargeIndex:block:[283,0,0],thread:[56,0,0]Assertion`srcIndex<srcSelectDimSize`failed./pytorch/aten/src/ATen/native/cuda/Indexing.cu:699:indexSele......
  • 物流系统原有40T数据加上每天至少要比之前多3G数据产品,这种该怎么解决
            今天早上接到一个学生的电话,说他现在有40T物流数据,且今年比去年每天至少要多3G数据,访问量也要比去年每天多1千万次。在少量增加成本或是在原有的服务器的前提下,将系统进行升级及拓展。希望我给他提供方案。    听完之后,首先我问题物流业务的安排(主要......
  • CloseableHttpResponse当程序进入 catch 块的情况下,就不得不在catch 中获取entity,这
    如果程序进入catch块时还需要获取responseentity,但此时try-with-resources会自动关闭资源,导致无法再从response中获取数据,这种情况下,你可以避免在try-with-resources中立即关闭CloseableHttpResponse,并延迟处理资源的关闭。为了解决这个问题,下面是几种可行的方式:1.......
  • 欧美的几种社会顶层规划非常先进,中国只有利用了这种规划才会和欧美竞争;如果能设计出更
    1、第一种先进的社会制度是科研体系制度。   科研体系制度的先进的地方,是可以集中全人类的财力、物力、人力推进科学和技术的发展。论文制度是科研制度的一个关键子项。论文指导让各个领域的研发都是高效信息共享,互通有无,相互之间既有合作,又有竞争。这个制度可以说是现代社......
  • 出现这种报错怎么办?SQLSTATE[HY000]: General error: 1615 Prepared statement needs
    如果你遇到由于数据库配置问题导致前后台无法打开的情况,可以通过修改数据库配置文件来解决。具体步骤如下:解决步骤第一步:打开数据库配置文件使用Notepad++打开配置文件:使用Notepad++或其他专业文本编辑器打开数据库配置文件 application/database.php。例如,假设你的......
  • 【人生感悟】真正厉害的人,这种思维都很强大
    我们都身处信息爆炸的时代,各种资讯蜂拥而至,很难保证所接收的信息都是准确的。在这样的情况下,拥有“穿透迷雾,直击核心”的能力非常关键。虽然钻研各个领域的专业知识可以帮助我们避免信息误导,但这个过程可能超出我们想象地漫长。事实上,真正厉害的人都有一个共同点——他们善于......