题解 P5320 - [BJOI2019]勘破神机(推式子+第一类斯特林数)
神仙题(为什么就没能自己想出来呢/zk/zk)
这是我 AC 的第 \(2\times 10^3\) 道题哦
首先考虑 \(m=2\) 的情况,我们首先可以想到一个非常 trivial 的 DP:\(dp_i\) 表示填好前 \(i\) 列的方案数,那么第 \(i\) 列显然有横着放和竖着放两种可能,方案数分别是 \(dp_{i-2}\) 和 \(dp_{i-1}\),因此我们有 \(dp_i=dp_{i-2}+dp_{i-1}\),边界条件 \(dp_0=1\),显然这个递推式与斐波那契数列有非常紧密的联系,具体来说 \(dp_i=f_{i+1}\)。因此我们可以将 \(L,R\) 分别加一,那么答案可以表示成:
\]
一脸不好用正常方法维护的样子。
不过注意到对于斐波那契数列而言我们有一个通项公式 \(f_i=\dfrac{1}{\sqrt{5}}((\dfrac{1+\sqrt{5}}{2})^n-(\dfrac{1-\sqrt{5}}{2})^n)\),因此我们考虑在这个通项公式上做点手脚。方便起见下文中记 \(A=\dfrac{1}{\sqrt{5}},B=-\dfrac{1}{\sqrt{5}},X=\dfrac{1+\sqrt{5}}{2},Y=\dfrac{1-\sqrt{5}}{2}\),那么 \(f_i=AX^i+BY^i\)。有人会说,这 \(\sqrt{5}\) 无理数都出来了,况且 \(\sqrt{5}\) 还在组合数上指标上,那不是更不好维护了吗?别急,\(\sqrt{5}\) 这样的无理数确实和阶乘幂不太搭,不过别忘了我们还有个阶乘幂转下降幂的公式:\(x^{\underline{k}}=\sum\limits_{i=0}^k\begin{bmatrix}k\\i\end{bmatrix}(-1)^{k-i}x^i\),因此 \(\dbinom{f_i}{k}=\dbinom{1}{k!}f_i^{\underline{k}}=\dfrac{1}{k!}\sum\limits_{j=0}^k\begin{bmatrix}k\\j\end{bmatrix}(-1)^{k-j}f_i^j\),因此我们有:
ans&=\sum\limits_{i=L}^R\dbinom{f_i}{k}\\
&=\dfrac{1}{k!}\sum\limits_{i=L}^R\sum\limits_{j=0}^k\begin{bmatrix}k\\j\end{bmatrix}(-1)^{k-j}f_i^j\\
&=\dfrac{1}{k!}\sum\limits_{i=L}^R\sum\limits_{j=0}^k\begin{bmatrix}k\\j\end{bmatrix}(-1)^{k-j}(AX^i+BY^i)^j\\
&=\dfrac{1}{k!}\sum\limits_{i=L}^R\sum\limits_{j=0}^k\begin{bmatrix}k\\j\end{bmatrix}(-1)^{k-j}\sum\limits_{p=0}^j\dbinom{j}{p}(AX^i)^p(BY^i)^{j-p}\\
&=\dfrac{1}{k!}\sum\limits_{j=0}^k\begin{bmatrix}k\\j\end{bmatrix}(-1)^{k-j}\sum\limits_{p=0}^j\dbinom{j}{p}A^pB^{j-p}\sum\limits_{i=L}^R(X^pY^{j-p})^i
\end{aligned}
\]
前面都可以在 \(\mathcal O(k^2)\) 时间内枚举得出,后面可以一波等比数列求和公式带走,时间复杂度 \(k^2\log R\)。
有几个细节需要注意:
- 注意特判 \(X^pY^{j-p}=1\) 的情况
- 由于 \(5\) 在 \(\bmod 998244353\) 意义下无二次剩余(凉 心 出 题 人),因此我们需要像二次剩余那样将数域由 \(\mathbb{R}\) 扩展到 \(\mathbb{Z}_5=\{a+b\sqrt{5}|a,b\in\mathbb{R}\}\)(瞎起名字 ing),加减乘除照样定义,这样就可以避免这个问题了。
这个故事告诉我们,有时候遇到斐波那契数列有关的题,即使模数不那么友好也能套通项公式/ts
接下来考虑 \(m=3\),首先 \(n\) 是奇数的情况答案肯定是 \(0\),我们 duck 不必管他们。对于 \(n\) 是偶数的情况咱们还是先从最 naive 的 DP 入手,那么最后一列可以三个横着的 \(1\times 2\) 多米诺骨牌,方案数 \(dp_{i-2}\),也可以是第一行放一个横着的骨牌,下面两列各放一个竖着的骨牌,当然也可以 reverse 一下,横着的骨牌放在第三行,方案数 \(2dp_{i-2}\),还可以第一行来一个横着的骨牌,紧接着下面跟着一个竖着的骨牌,紧接着左边又是 \(2k(k\in[1,\infty)\cap\mathbb{Z})\) 个横着的骨牌,最后又一个竖着的,那么此时应从 \(dp_{i-2k-2}\) 转移过来,方案数 \(2dp_{i-2k-2}\),因此我们有
\]
前缀和搞搞可以变成:
\]
如果我们设 \(g_n=dp_{2n}\),那么上式可写作 \(g_i=4g_{i-1}-g_{i-2}\)。
喜闻乐见的 \(a_i=Aa_{i-1}+Ba_{i-2}\) 的形式,列出特征根方程 \(1=4x-x^2\),解出它的两个根为 \(x_1=2+\sqrt{3},x_2=2-\sqrt{3}\),然后套个待定系数法,设 \(g_i=Ax_1^i+Bx_2^i\),那么:
A+B=1\\
(2+\sqrt{3})A+(2-\sqrt{3})B=3
\end{cases}
\]
解得
A=\dfrac{3+\sqrt{3}}{6}\\
B=\dfrac{3-\sqrt{3}}{6}
\end{cases}
\]
然后就和 \(m=2\) 的情况一样了。
然鹅由于太久没有接触普通幂与阶乘幂之间的转换,一开始甚至把第一类斯特林数敲成了第二类斯特林数……这里稍微澄清一下:
- 用阶乘幂表示普通幂用第二类斯特林数,以等式 \(x^k=\sum\limits_{i=0}^k\begin{Bmatrix}k\\i\end{Bmatrix}x^{\underline{i}}\) 为例,如果我们把等号左右两边叫做一区和二区,那么下划线在哪个区就用第几类斯特林数。
- 用大幂表示小幂需要加 \((-1)^{k-i}\)
const int MAXK=501;
const int MOD=998244353;
int qpow(int x,int e){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
return ret;
}
int fac[MAXK+5],ifac[MAXK+5],s[MAXK+5][MAXK+5];
void init_fac(int n){
for(int i=(fac[0]=ifac[0]=ifac[1]=1)+1;i<=n;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i-1]*ifac[i]%MOD;
s[0][0]=1;for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) s[i][j]=(s[i-1][j-1]+1ll*(i-1)*s[i-1][j])%MOD;
}
int sq;
struct comp{
int x,y;
comp(int _x=0,int _y=0):x(_x),y(_y){}
comp operator +(const comp &rhs){return comp((x+rhs.x)%MOD,(y+rhs.y)%MOD);}
comp operator -(const comp &rhs){return comp((x-rhs.x+MOD)%MOD,(y-rhs.y+MOD)%MOD);}
comp operator *(const comp &rhs){return comp((1ll*x*rhs.x+1ll*y*rhs.y%MOD*sq)%MOD,(1ll*x*rhs.y+1ll*y*rhs.x)%MOD);}
comp operator /(const comp &rhs){
ll inv=qpow((1ll*rhs.x*rhs.x%MOD-1ll*sq*rhs.y%MOD*rhs.y%MOD+MOD)%MOD,MOD-2);
return comp(1ll*(1ll*x*rhs.x%MOD-1ll*y*rhs.y%MOD*sq%MOD+MOD)*inv%MOD,1ll*(1ll*y*rhs.x%MOD-1ll*x*rhs.y%MOD+MOD)*inv%MOD);
}
bool operator ==(const comp &rhs){return (!(x^rhs.x)&&!(y^rhs.y));}
} A,B,X,Y;
int binom(int x,int y){return 1ll*fac[x]*ifac[y]%MOD*ifac[x-y]%MOD;}
comp qpow_c(comp x,ll e){
comp res(1);
for(;e;e>>=1,x=x*x) if(e&1) res=res*x;
return res;
}
comp getsum(comp bs,ll t){
if(t<0) return comp();
if(bs==comp(1)) return comp((t+1)%MOD,0);
return (qpow_c(bs,t+1)-comp(1))/(bs-comp(1));
}
comp getsum(comp bs,ll l,ll r){return getsum(bs,r)-getsum(bs,l-1);}
int solve(ll l,ll r,int k){
if(l>r) return 0;comp res;
for(int j=0;j<=k;j++){
comp sum=comp();
for(int p=0;p<=j;p++){
comp mul(1);
mul=mul*comp(binom(j,p))*qpow_c(A,p)*qpow_c(B,j-p);
mul=mul*getsum(qpow_c(X,p)*qpow_c(Y,j-p),l,r);
sum=sum+mul;
} sum=sum*comp(s[k][j]);
// printf("%d %d\n",sum.x,sum.y);
if((k-j)&1) res=res-sum;
else res=res+sum;
} return 1ll*res.x*ifac[k]%MOD;
}
int main(){
int qu,opt;scanf("%d%d",&qu,&opt);init_fac(MAXK);
if(opt==2){
sq=5;A=comp(0,1)/comp(5);B=comp(0,MOD-1)/5;
X=comp(1,1)/comp(2);Y=comp(1,MOD-1)/comp(2);
} else {
sq=3;A=comp(3,1)/comp(6);B=comp(3,MOD-1)/comp(6);
X=comp(2,1);Y=comp(2,MOD-1);
} while(qu--){
ll l,r;int k;scanf("%lld%lld%d",&l,&r,&k);
if(opt==2) printf("%d\n",1ll*qpow((r-l+1)%MOD,MOD-2)*solve(l+1,r+1,k)%MOD);
else printf("%d\n",1ll*qpow((r-l+1)%MOD,MOD-2)*solve(l+1>>1,r>>1,k)%MOD);
}
return 0;
}
题解 P5320 - [BJOI2019]勘破神机(推式子+第一类斯特林数)的更多相关文章
- luogu P5320 [BJOI2019]勘破神机
传送门 首先我们要知道要求什么.显然每次放方块要放一大段不能从中间分开的部分.设\(m=2\)方案为\(f\),\(m=3\)方案为\(g\),\(m=2\)可以放一个竖的,或者两个横的,所以\(f_ ...
- [BJOI2019]勘破神机
[BJOI2019]勘破神机 推式子好题 m=2,斐波那契数列,$f_{n+1}$项 不妨$++l,++r$,直接求$f_n$ 求$\sum C(f_n,k)$,下降幂转化成阶乘幂,这样都是多项式了, ...
- [BJOI2019]勘破神机(斯特林数,数论)
[BJOI2019]勘破神机(斯特林数,数论) 题面 洛谷 题解 先考虑\(m=2\)的情况. 显然方案数就是\(f_i=f_{i-1}+f_{i-2}\),即斐波那契数,虽然这里求出来是斐波那契的第 ...
- [BJOI2019]勘破神机(斯特林数+二项式定理+数学)
题意:f[i],g[i]分别表示用1*2的骨牌铺2*n和3*n网格的方案数,求ΣC(f(i),k)和ΣC(g(i),k),对998244353取模,其中l<=i<=r,1<=l< ...
- #loj3090 [BJOI2019] 勘破神机
简单线性代数练习题 首先翻开具体数学生成函数一章,可以发现\(F(n),G(n)\)满足以下递推式 \[F(n)=F(n-1)+F(n-2),F(0)=1,F(1)=1\] \[G(n)=4G(n-2 ...
- [BJOI2019]勘破神机(第一类斯特林数,斐波那契数列)
真的是好题,只不过强行多合一有点过分了…… 题目大意: $T$ 组数据.每个测试点中 $m$ 相同. 对于每组数据,给定 $l,r,k$,请求出 $\dfrac{1}{r-l+1}\sum\limit ...
- 【LOJ】#3090. 「BJOI2019」勘破神机
LOJ#3090. 「BJOI2019」勘破神机 为了这题我去学习了一下BM算法.. 很容易发现这2的地方是\(F_{1} = 1,F_{2} = 2\)的斐波那契数列 3的地方是\(G_{1} = ...
- LOJ 3090 「BJOI2019」勘破神机——斯特林数+递推式求通项+扩域
题目:https://loj.ac/problem/3090 题解:https://www.luogu.org/blog/rqy/solution-p5320 1.用斯特林数把下降幂化为普通的幂次求和 ...
- loj 3090 「BJOI2019」勘破神机 - 数学
题目传送门 传送门 题目大意 设$F_{n}$表示用$1\times 2$的骨牌填$2\times n$的网格的方案数,设$G_{n}$$表示用$1\times 2$的骨牌填$3\times n$的网 ...
随机推荐
- css单位px,em,rem区别
在css中单位长度用的最多的是px.em.rem,这三个的区别是: px是固定的像素,一旦设置了就无法因为适应页面大小而改变. em和rem相对于px更具有灵活性,他们是相对长度单位,意思是长度不是定 ...
- 3.2 Dependencies of the Projects in the Solution 解决方案中项目间的依赖项
3.2 Dependencies of the Projects in the Solution 解决方案中项目间的依赖项 The diagram below shows the essential ...
- ES2020新特性记录
1.可选链操作符 // oldlet ret = obj && obj.first && obj.first.second// newlet ret = obj?.fi ...
- MAC 安装 apache ab 压力测试工具以及遇到的坑
ab 是apache对 http服务器进行压力测试的工具,它可以测试出服务器每秒可以处理多少请求.本文记录mac版本安装 ab 的步骤以及遇到的坑. 下载 进入 apache ab官网 下载页面. 安 ...
- AtCoder Beginner Contest 224
AtCoder Beginner Contest 224 A - Tires 思路分析: 判断最后一个字符即可. 代码如下: #include <bits/stdc++.h> using ...
- spring security整合QQ登录
最近在了解第三方登录的内容,尝试对接了一下QQ登录,此次记录一下如何实现QQ登录的过程,在这个例子中是和spring secuirty整合的,不整合spring secuirty也是一样的. 需求: ...
- Noip模拟79 2021.10.17(题目名字一样)
T1 F 缩点缩成个$DAG$,然后根据每个点的度数计算期望值 1 #include<cstdio> 2 #include<cstring> 3 #include<vec ...
- 你知道怎么从jar包里获取一个文件的内容吗
目录 背景 报错的代码 原先的写法 编写测试类 找原因 最终代码 背景 项目里需要获取一个excle文件,然后对其里的内容进行修改,这个文件在jar包里,怎么尝试都读取不成功,但是觉得肯定可以做到,因 ...
- 连续子序列的最大和 牛客网 剑指Offer
连续子序列的最大和 牛客网 剑指Offer 题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量 ...
- cf 11B Jumping Jack(贪心,数学证明一下,,)
题意: 给一个数X. 起始点为坐标0.第1步跳1格,第2步跳2格,第3步跳3格,.....以此类推. 每次可以向左跳或向右跳. 问最少跳几步可以到坐标X. 思路: 假设X是正数. 最快逼近X的方法是不 ...