关于T4的一些奥妙重重的题解。

实际上题解还算人话(,但是有些细节的地方有些吊诡。而且鉴于大家大概没学过任何生成函数理论那来普及一波。还可以水博客。

首先解释一下开头那个诡异的式子。

我们看见这个题一般都是先打个表。

0 1 2 3 4 5 6 7 8 9 10
1 1
2 1 1
3 1 2 2 1
4 1 3 5 6 5 3 1
5 1 4 9 15 20 22 20 15 9 4 1

(joke3579跟我说这玩意有用吗,我的评价是管有没有用先打上)

实际上这玩意确实没有用,但是很优美(

然后回顾一下我们关于逆序对个数的 \(dp\) 式子:设 \(dp[i][j]\)\(i\) 长度的排列,有 \(j\) 个逆序对的方案数,我们每次插入数 \(i\) ,可以得到:

\[dp[i][j]=\sum_{k=\min(0,j-i+1)}^jdp[i-1][k] \]

然后我们看第 \(i\) 行每个数对于下一行位置的贡献。发现: 第 \(0\) 列可以加到下一行的 \(0,1,\dots,i\) 上,第 \(1\) 列可以加到下一行的 \(1,2,\dots,i+1\) 上,以此类推。这启示我们使用形式幂级数解决问题。

我们设第 \(n\) 行的答案的生成函数为 \(F_n(x)\) 。如果您不知道这是个什么东西的话可以理解成这是个无穷级数,第 \(x^i\) 项的系数就是上面那个表第 \(n\) 行第 \(i\) 列的答案。

那么如果我们把它乘一个 \(x\) 那所有的系数就相当于向右挪了一位。因此上面的就相当于加上挪 \(0\) 位,挪 \(1\) 位,挪 \(2\) 位,一直到 \(n-1\) 位。也就是

\[\begin{aligned} F_{n}(x)&=(\sum_{i=0}^{n-1}x^i)F_{n-1}(x)\\ &=F_{n-1}(x)\frac{1-x^n}{1-x} \end{aligned} \]

后面那一步就是个等比数列求和。

然后我们发现第 \(1\) 行只有 \(0\) 列是个 \(1\) ,那不就是 \(1\) 吗。所以我们有第 \(n\) 行的答案就是:

\[\prod_{i=1}^n\frac{1-x^i}{1-x} \]

然后我们把它拆开成上下两部分。上面的部分:

\[\prod_{i=1}^n1-x^i \]

我们有一个奥妙重重的结论:

\[\prod_{i=1}1-x^i=1+\sum_{i=1}(-1)^ix^{\frac{3i(i\pm1)}2} \]

具体的bdfs“五边形数定理”。证明不重要,欧拉也拖了十年才发结论。然后观察到后面指数是个 \(i\times i\) 的东西所以它只有 \(O(\sqrt n)\) 项,暴力求就行。

然后是下面的东西:

\[(1-x)^{-n} \]

广义二项式定理:

\[\begin{aligned} &\sum_k\binom{-n}k(-x)^k\\ =&\sum_k(-1)^k\binom{-n}kx^k \end{aligned} \]

使用上指标反转:(如果您不知道的话翻具体数学或者看我曾经的某些东西

\[\sum_k\binom{k+n-1}kx^k \]

然后我们是 \(\mod 2\) 意义下计算的,所以只需要 \(\binom{k+n-1}{n-1}\mod 2\) 的值。

上Lucas定理,发现 \(\mod 2\) 就相当于把上下指标都拆成二进制位算组合数乘起来。然后要求所有的结果都是 \(1\) ,那么就是所有 \(n-1\) 在二进制位有值的地方 \(k+n-1\) 也必须有值,就是

\[[(n-1)\&(k+n-1)=n-1]=[i\&(n-1)=0] \]

后面转换显然,读者自证不难。

那么这个东西其实就是 \(\prod_{2^t\&(n-1)=0}1+x^{2^t}\)

所以我们直接扫 \(n-1\) 的每个二进制位,开个bitset算就行了。乘一个 \(x^{2^t}\) 相当于异或上左移之后的值。复杂度 \(O(\frac{n\log n}{\omega})\)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <bitset>
using namespace std;
int n,m;
bitset<100000001>a;
int main(){
    scanf("%d%d",&n,&m);
    a[0]=1;
    for(int i=1;;i++){
        if(i*(3*i+1)/2<=n)a[i*(3*i+1)/2]=1;
        if(i*(3*i-1)/2<=n)a[i*(3*i-1)/2]=1;
        else break;
    }
    for(int i=0;i<=__lg(n);i++){
        if(((1<<i)&(n-1))==0)a^=(a<<(1<<i));
    }
    while(m--){
        int x;scanf("%d",&x);
        a[x]?putchar('1'):putchar('0');
    }
    return 0;
}

好您现在看完了。请问我以后还需不需要把每一步都解释一遍?请留下评论。

原文地址:http://www.cnblogs.com/gtm1514/p/16794314.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性