CF960G Bandit Blues

题目链接:洛谷

题目描述:在一个$1,2,\ldots,n$的排列中,设前面没有数比它大的数有$a$个,后面没有数比它大的数有$b$个,已知$n$,$a$,$b$,求这样的序列个数。

数据范围:$1\leq a,b\leq n\leq 10^5$


这道题看上去不是那么好入手,我们先看看只有一个限制$a$该怎么做。

考虑dp,假设在一个$i$个数的排列中,$j$表示前面没有数比它大的数的个数。

我们要找一个好计算贡献的数,显然最小的数如果在第一位,那它就可以贡献,否则不行。

$$dp[i][j]=dp[i-1][j-1]+(i-1)dp[i-1][j]$$

然后就知道为什么这题是$n\leq 10^5$和3500ms了(滑稽

这显然就是第一类Stirling数,虽然并没有什么公式,但是我们也可以通过FFT预处理,这个待会儿再讲。


我们现在可以考虑$b$了。

我们知道,最大的数$n$是唯一一个对$a$和$b$都有贡献的数,而且$n$前面的只对$a$有贡献,$n$后面的只对$b$有贡献(因为没有数比$n$大)

所以我们考虑$n$的位置在$i$,所以

$$Ans=\sum_{i=1}^ns(i-1,a-1)s(n-i,b-1)C_{n-1}^{i-1}$$

显然这个式子还要进行化简,但是$s(n,m)$又没有通项公式,怎么化简?

这时候就要请出非常巧妙的组合意义来进行推导。

$Ans$是在$n-1$个元素中先选出$i-1$个,然后再分别将$i-1$个和剩下的$n-i$个组成$a-1$和$b-1$个圆排列(这是根据元素个数来枚举)

也是$n-1$个元素组成$a+b-2$个圆排列,然后再这$a+b-2$个圆排列中选$a-1$个(这是根据圆排列直接枚举),因此得知

$$Ans=s(n-1,a+b-2)*C_{a+b-2}^{a-1}$$

其实我们在考虑证明一些组合恒等式的时候,可以通过组合意义来证明,有时非常简洁。

然后您就可以顺便把P4609 [FJOI2016]建筑师给切了。(这是本题的弱化版)


现在唯一的问题就是如何快速计算第一类Stirling数。

在这里放个结论

$$\sum_{i=0}^nS(n,i)x^i=\prod_{i=0}^{n-1}(x+i)$$

(这里留坑,以后写下证明)

也就是说我们可以计算它的生成函数了。

右边那部分可以通过分治的方法计算,然后复杂度$T(n)=2T(\frac{n}{2})+O(n\log n)$,由主定理计算得复杂度$O(n\log^2n)$

 1 #include<bits/stdc++.h>
 2 #define Rint register int
 3 using namespace std;
 4 typedef long long LL;
 5 const int N = 400003, mod = 998244353, G = 3, Gi = 332748118;
 6 int n, a, b;
 7 inline int kasumi(int a, int b){
 8     int res = 1;
 9     while(b){
10         if(b & 1) res = (LL) res * a % mod;
11         a = (LL) a * a % mod;
12         b >>= 1;
13     }
14     return res;
15 }
16 int rev[N];
17 inline void NTT(int *A, int limit, int type){
18     for(Rint i = 0;i < limit;i ++)
19         if(i < rev[i]) swap(A[i], A[rev[i]]);
20     for(Rint mid = 1;mid < limit;mid <<= 1){
21         int Wn = kasumi(type == 1 ? G : Gi, (mod - 1) / (mid << 1));
22         for(Rint j = 0;j < limit;j += mid << 1){
23             int w = 1;
24             for(Rint k = 0;k < mid;k ++, w = (LL) w * Wn % mod){
25                 int x = A[j + k], y = (LL) w * A[j + k + mid] % mod;
26                 A[j + k] = (x + y) % mod;
27                 A[j + k + mid] = (x - y + mod) % mod;
28             }
29         }
30     }
31     if(type == -1){
32         int inv = kasumi(limit, mod - 2);
33         for(Rint i = 0;i < limit;i ++)
34             A[i] = (LL) A[i] * inv % mod;
35     }
36 }
37 int A[20][N];
38 inline void solve(int now, int l, int r){
39     if(l == r){
40         A[now][0] = l;                            // f(x) = x + l
41         A[now][1] = 1;
42         return;
43     }
44     int mid = l + r >> 1;
45     solve(now + 1, l, mid);
46     for(Rint i = 0;i <= mid - l + 1;i ++) A[now][i] = A[now + 1][i];        // 注意这里不能用memset,否则复杂度不对 
47     solve(now + 1, mid + 1, r);
48     int limit = 1, L = -1;
49     while(limit <= r - l + 1){limit <<= 1; L ++;}
50     for(Rint i = 0;i < limit;i ++)
51         rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << L);
52     for(Rint i = mid - l + 2;i < limit;i ++) A[now][i] = 0;
53     for(Rint i = r - mid + 1;i < limit;i ++) A[now + 1][i] = 0;
54     NTT(A[now], limit, 1); NTT(A[now + 1], limit, 1);
55     for(Rint i = 0;i < limit;i ++)
56         A[now][i] = (LL) A[now][i] * A[now + 1][i] % mod;
57     NTT(A[now], limit, -1);
58 }
59 inline int fac(int n){
60     int res = 1;
61     for(Rint i = 2;i <= n;i ++) res = (LL) res * i % mod;
62     return res;
63 }
64 inline int C(int n, int m){
65     if(n < m) return 0;
66     return (LL) fac(n) * kasumi((LL) fac(m) * fac(n - m) % mod, mod - 2) % mod;
67 }
68 int main(){
69     scanf("%d%d%d", &n, &a, &b);
70     if(!a || !b || n + 1 < a + b){puts("0"); return 0;}
71     if(n == 1){puts("1"); return 0;}
72     solve(0, 0, n - 2);
73     printf("%d\n", (LL) A[0][a + b - 2] * C(a + b - 2, a - 1) % mod);
74 }
CF960G

 

转载于:https://www.cnblogs.com/AThousandMoons/p/10585384.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于PyTorch的Embedding和LSTM的自动写诗实验LSTM (Long Short-Term Memory) 是一种特殊的循环神经网络(RNN)架构,用于处理具有长期依赖关系的序列数据。传统的RNN在处理长序列时往往会遇到梯度消失或梯度爆炸的问题,导致无法有效地捕捉长期依赖。LSTM通过引入门控机制(Gating Mechanism)和记忆单元(Memory Cell)来克服这些问题。 以下是LSTM的基本结构和主要组件: 记忆单元(Memory Cell):记忆单元是LSTM的核心,用于存储长期信息。它像一个传送带一样,在整个链上运行,只有一些小的线性交互。信息很容易地在其上保持不变。 输入门(Input Gate):输入门决定了哪些新的信息会被加入到记忆单元中。它由当前时刻的输入和上一时刻的隐藏状态共同决定。 遗忘门(Forget Gate):遗忘门决定了哪些信息会从记忆单元中被丢弃或遗忘。它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 输出门(Output Gate):输出门决定了哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。同样地,它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 LSTM的计算过程可以大致描述为: 通过遗忘门决定从记忆单元中丢弃哪些信息。 通过输入门决定哪些新的信息会被加入到记忆单元中。 更新记忆单元的状态。 通过输出门决定哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。 由于LSTM能够有效地处理长期依赖关系,它在许多序列建模任务中都取得了很好的效果,如语音识别、文本生成、机器翻译、时序预测等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值