zoukankan      html  css  js  c++  java
  • 【洛谷6672】[清华集训2016] 你的生命已如风中残烛(Raney引理)

    点此看题面

    • 共有(m)张牌,其中(n)张牌上写有数字(w_i),满足(sum w_i=m)
    • 一开始你先摸走牌库最顶上的一张牌,每当你摸到一张写着数字(x)的牌,你就再摸(x)张牌。
    • 问有多少种牌库,你能把所有牌摸完。
    • (nle40,w_ile10^5)

    (Raney)引理

    做这道题必需的一个引理:

    一个环(x_1,x_2,...,x_n)满足(sum x_i=1),在将它裂开形成的(n)条可能的链中,恰有一条满足所有前缀和都是正数。

    懒得另开一篇博客,就在这里顺便讲一下用(Raney)引理证明卡特兰数(C_n=frac{(2n)!}{n!(n+1)!})

    因为共有(n)(1)(n)(-1),它们的和不为(1),因此我们强行在序列开头加上一个(1),这样就满足所有数和为(1)

    由于所有前缀和为正数,因此第一个数肯定是(1)而不是(-1),那么去掉开头就变成了剩余所有前缀和非负,恰好满足卡特兰数的限制条件。

    这样就能推导出卡特兰数的通项公式(C_n=frac{(2n)!}{n!(n+1)!})

    关于此题的解法

    首先我们把所有数都减去(1),此时所有数和为(0),且需要满足所有前缀都是非负数。

    一个(naive)的想法是和前面卡特兰数的推导一样,强行在序列开头加上一个(1),满足所有数和为(1),且变成所有前缀都是正数。

    但是,毕竟还是不一样,因为卡特兰数中正数只有(1),开头必须是(1),而这道题则不一定,所以会计算出错。

    于是我们必须换个思路,发现有一个东西是唯一的,就是负数只有(-1)

    所以我们改成在序列末尾加上一个(-1),那么序列总和是(-1),这样一来只要将所有数都取反并逆序,就转化成了(Raney)引理的标准模型,且可以保证计算不重复(因为取反后的正数就只有(1)了)。

    此时共有(m+1)个数,因此圆排列数量应该是((m+1-1)!=m!)

    然后为了除掉这个(-1)的影响,考虑原本有(m-n)(-1),现在添上一个(-1)就有(m-n+1)(-1),为了消除贡献还需要将(m!)除去(m-n+1)

    因此答案就是:

    [frac{m!}{m-n+1} ]

    因为(m-n+1le m),所以只要在求阶乘的时候忽略其影响即可。

    代码:(O(sum w_i))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 40
    #define X 998244353
    using namespace std;
    int n,m;
    int main()
    {
    	RI i,t;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&t),m+=t;//m为所有数的总和
    	for(t=i=1;i<=m;++i) i^(m-n+1)&&(t=1LL*t*i%X);return printf("%d
    ",t),0;//计算答案,忽略m-n+1
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    第3次作业:卷积神经网络
    第一次作业:深度学习基础
    CSS基础总结
    Java 9.Spring--AOP
    Java 8.Spring--整合Junit测试
    Java 7.Spring--使用注解
    Java 6.Spring--对象的依赖关系-复杂类型注入
    Java 5.Spring的依赖注入
    Java 4.Spring的对象创建的方法
    Java 3.Spring的对象创建的细节
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu6672.html
Copyright © 2011-2022 走看看