【题解】P9035 「KDOI-04」Pont des souvenirs
P9035 「KDOI-04」Pont des souvenirs
题意
给定正整数 \(n,k\),求有多少个长度为 \(n\) 的正整数序列 \(a\) 满足:
- \(0<a_1\le a_2\le a_3\le\cdots\le a_n\le k\);
- \(\forall\ i\not=j\),\(a_i+a_j\le k+1\)。
答案对 \(10^9+7\) 取模。
题解
知识点:组合数。
启发:
-
组合数求和。
-
插板法。
不追求严谨证明的话,这题是极为简单的,得到 \(O(nk)\) 的递推做法后把 dp 数组列出来,对着杨辉三角找规律就结束了。
这里提供一种基于隔板法的推法。
首先得知道这个恒等式。
\[\large \displaystyle \sum_{i=1}^k\binom{n+i}{i-1}=\binom{n+k+1}{k-1}
\]
这是组合数平行求和公式的一种形式,用归纳法可以证明,这里就不证了。
当 \(n=1\) 时,答案显然为 \(k\)。
现在讨论 \(n\ge 2\) 时的情况。
\(a\) 是非严格单调递增的,故第二条限制可以转化为,\(a_{n-1}+a_{n}\le k+1\)。
考虑枚举 \(a_{n}\) 和 \(a_{n-1}\),分别设为 \(i,j\),则 \(i\) 枚举范围是 \(1\sim k\),\(j\) 则为 \(1\sim \min\{k+1-i,i\}\),这样枚举出来的一定是合法的。
现在考虑对于某对 \(i,j\),如何求出 \(a_1\sim a_{n-2}\) 取值方法数。
由于 \(a\) 非严格单调递增,故可以用隔板法来求,不过某些值是可以一个都不取的,还要增加 \(j\) 个空。
假设读者已经了解隔板法,下面直接给出推出的式子。
\[\large \binom{(n-2-1)+j}{j-1}=\binom{n+j-3}{j-1}
\]
故答案可以表示为如下和式。
\[\displaystyle \large \sum_{i=1}^k \sum_{j=1}^{\min\{k+1-i,i\}} \binom{n+j-3}{j-1}
\]
根据上文提到的恒等式,可以去掉一个和式。
\[\displaystyle \large \sum_{i=1}^k \binom{n+\min\{k+1-i,i\}-2}{\min\{k+1-i,i\}-1}
\]
式子中的 \(\min\) 很难看,考虑把式子拆成两段。
\[\displaystyle \large \sum_{i=1}^{\lfloor \frac{k}{2} \rfloor} \binom{n+i-2}{i-1}+\sum_{i=1}^{\lceil \frac{k}{2} \rceil} \binom{n+i-2}{i-1}
\]
再次使用上文的恒等式,得到最终的答案式子。
\[\displaystyle \large \binom{n+\lfloor \frac{k}{2} \rfloor-1}{\lfloor \frac{k}{2} \rfloor-1}+\binom{n+\lceil \frac{k}{2} \rceil-1}{\lceil \frac{k}{2} \rceil-1}=\displaystyle \large \binom{n+\lfloor \frac{k}{2} \rfloor-1}{n}+\binom{n+\lceil \frac{k}{2} \rceil-1}{n}
\]
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 20000010
#define int long long
const int mod=1e9+7;
namespace comb{
int fac[N];
inline int inv(int a){
int b=mod-2,ans=1;
while(b){
if(b&1){
ans=ans*a%mod;
}
a=a*a%mod;
b>>=1;
}
return ans;
}
inline int C(int n,int m){
if(n<m){
return 0;
}
return fac[n]*inv(fac[m])%mod*inv(fac[n-m])%mod;
}
inline void init(int lim){
fac[0]=1;
rep(i,1,lim){
fac[i]=fac[i-1]*i%mod;
}
}
}
using comb::C;
inline void sol(){
int n,k;
cin>>n>>k;
if(n==1){
cout<<k<<"\n";
return;
}
cout<<(C(n-1+k/2,n)+C(n-1+(k-1)/2+1,n))%mod<<"\n";
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
comb::init(2e7);
int t;
cin>>t;
while(t--){
sol();
}
return 0;
}

浙公网安备 33010602011771号