zoukankan      html  css  js  c++  java
  • P5401 [CTS2019]珍珠

    题目链接

    大力推式子。

    容易想到需要满足的条件是:

    [sum_i cnt_i mod 2 <= n - 2m ]

    好啦我自己想到的部分就到此为止啦

    不知道怎么想到的二项式反演:计算钦定(i) 种颜色出现了奇数次的方案数 (g_i),一会儿再说怎么转化成“恰好”的方案数。

    接下来需要用到生成函数。有一些需要知道的常识(下面均为EGF,下标从0开始):

    [<1,1,1,1,1,...>=e^x ]

    [<1,-1,1,-1,1>=e^{-x} ]

    [large<0,1,0,1,0,1,...>=frac{e^x-e^{-x}}{2} ]

    [large e^{ax}=<1,a,a^2,a^3,...> ]

    然后有:

    [large g_i= {Dchoose i} n![x^n](frac{e^x-e^{-x}}{2})^i(e^x)^{d-i} ]

    二项式定理,拆组合数,化为卷积形式:

    [=(1/2^i) * {D choose i} n! [x^n]sum_{j}{ichoose j}(e^x)^j(-e^{-x})^{i-j}(e^x)^{D-i} ]

    [=frac{D!n!(-1)^i}{(D-i)!2^i}sum_{j}frac{(-1)^j}{j!} * frac{1}{(i-j)!} [x^n]e^{x(2j-2i+D)} ]

    [=frac{D!n!(-1)^i}{(D-i)!2^i}sum_{j}frac{(-1)^j}{j!} * frac{1}{(i-j)!} * frac{(D-2(i-j))^n}{n!} ]

    [=frac{D!(-1)^i}{(D-i)!2^i}sum_{j}frac{(-1)^j}{j!} * frac{(D-2(i-j))^n}{(i-j)!} ]

    [large A_k=frac{(-1)^k}{k!}, B_k=frac{(D-2k)^n}{k!},H_k=A_k*B_k ]

    [large g_i=frac{D!(-1)^i}{(D-i)!2^i}h_i ]

    这样我们就能够 (O(nlogn)) 求出 (g_i) 了。

    然后考虑二项式反演:

    [f_k=sum_{i}^D (-1)^{i-k} {ichoose k}g_i ]

    [=(1/k!) * sum_{i=0}^D i!g_i * frac{(-1)^{i-k}}{(i-k)!} ]

    仍然设 (A_i=i!g_i,B_i=frac{(-1)^i}{i!})

    那么:

    [f_k=(1/k!) * sum_{i} A_iB_{i-k} ]

    这需要一种特殊的卷积。翻转 (B) 数组,即 (B^r_{i}=B_{D-i}),则:

    [f_k=(1/k!)sum_iA_iB^r_{D-i+k} ]

    这样的话下标之和就是定值 (D+k) 了。

    [f_k=(1/k!)C_{D+k} ]

    关键代码:

    for (register int i = 0; i <= d; ++i) {
    	if (i & 1)	A[i] = P - jieni[i];
    	else	A[i] = jieni[i];
    	B[i] = quickpow(((d - 2 * i) % P + P) % P, n) * jieni[i] % P;
    }
    ntt(A, 1), ntt(B, 1);
    for (register int i = 0; i < limi; ++i)
    	h[i] = A[i] * B[i] % P, A[i] = B[i] = 0;
    ntt(h, -1);
    
    for (register int i = 0; i <= d; ++i) {
    	g[i] = (i & 1 ? -1 : 1) * jie[d] * jieni[d - i] % P * quickpow(quickpow(2, i), P - 2) % P * h[i] % P;
    	if (g[i] < 0)	g[i] += P;
    }
    for (register int i = 0; i <= d; ++i) {
    	A[i] = jie[i] * g[i] % P;
    	B[d - i] = (i & 1 ? -1 : 1) * jieni[i] % P;
    	if (B[d - i] < 0)	B[d - i] += P;
    }
    ntt(A, 1), ntt(B, 1);
    for (register int i = 0; i < limi; ++i)	f[i] = A[i] * B[i] % P, A[i] = B[i] = 0;
    ntt(f, -1);
    ll ans = 0;
    for (register int k = 0; k <= n - m - m; ++k) {
    	ans = (ans + jieni[k] * f[d + k]) % P;
    }
    
  • 相关阅读:
    Vue 路由组件传参的 8 种方式
    JS中通过url动态获取图片大小的方法小结(两种方法)
    基于 Vue.js 实现的精致移动端组件库
    .net core 通过代码创建数据库表
    .net core 框架调用顺序
    POCO的理解
    winform datagridview 同步滚动
    UseIIS
    winform 多个datagridview 之间同步滚动
    winform BackgroundWorker 的用法
  • 原文地址:https://www.cnblogs.com/JiaZP/p/13432118.html
Copyright © 2011-2022 走看看