*题解:P9035 「KDOI-04」Pont des souvenirs

题目链接

解析

考虑钦定最大值 \(a_n\),这样更小的元素可以在 \([1,\min (a_n,k + 1 - a_n)]\) 下任意选。序列单调不减意味着差分序列中元素均为非负数。记 \(b\)\(a\) 的差分序列,即 \(b_i = a_i - a_{i - 1}\),钦定最大值 \(a_n\),那么有 \(\sum_{i=1}^n b_i=a_n\)

\(\min (a_n,k + 1 - a_n) = a_n\),则直接插板即可,方案数为 \(\binom{a_n - 1 + n - 1}{n - 1}\)\(a_n - 1\) 是因为 \(b_1 = a_1 > 0\),所以在最开始分一个给它。考虑 \([1,\lfloor \frac{k}{2}\rfloor]\) 的所有 \(a_n\),此时 \(\min\) 取到 \(a_n\),方案数为 \(\sum_{i = 1}^{\lfloor \frac{k}{2}\rfloor} \binom{i + n - 2}{n - 1}\)

\(\min (a_n,k + 1 - a_n) = k + 1 - a_n\),则额外有限制 \(\sum_{i=1}^{n - 1} b_i \le k + 1 - a_n\),可以看作是只取 \([1,k + 1 - a_n]\) 这部分进行插板,方案数为 \(\binom{k + 1 - a_n - 1 + n - 1}{n - 1}\)。同理考虑 \([\lfloor \frac{k}{2}\rfloor + 1,k]\) 的所有 \(a_n\),方案数为 \(\sum_{i=\lfloor \frac{k}{2}\rfloor + 1}^{k} \binom{k - i + n - 1}{n - 1}\)

两种情况都讨论完了,直接做是 \(O(Tk)\) 的,无法通过,考虑优化。

考虑上指标求和公式:

\[\sum_{i=m}^n \binom{i}{m} = \binom{n + 1}{m + 1} \]

于是对于第一种情况,有:

\[\sum_{i = 1}^{\lfloor \frac{k}{2}\rfloor} \binom{i + n - 2}{n - 1}=\binom{n + \lfloor \frac{k}{2}\rfloor - 1}{n} \]

对于第二种情况,有:

\[\sum_{i=\lfloor \frac{k}{2}\rfloor + 1}^{k} \binom{k - i + n - 1}{n - 1}=\sum_{i=0}^{k - (\lfloor \frac{k}{2}\rfloor + 1)} \binom{i + n - 1}{n - 1} = \binom{n + k - \lfloor \frac{k}{2} \rfloor - 1}{n} \]

时间复杂度 \(O(n + k)\)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 2e7 + 10,mod = 1e9 + 7;
int fac[N],inv[N];
int C(int n,int m){
	if(m > n) return 0;
	return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod; 
}
int qmi(int a,int b){
	int res = 1;
	while(b){
		if(b & 1) res = 1ll * res * a % mod;
		a = 1ll * a * a % mod;
		b >>= 1;
	}
	return res;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);	
//	freopen("in.txt","r",stdin);
//	freopen("out1.txt","w",stdout);
	fac[0] = 1;
	for(int i=1;i<N;i++){
		fac[i] = 1ll * fac[i - 1] * i % mod;
	}
	inv[N - 1] = qmi(fac[N - 1],mod - 2);
	for(int i=N - 2;i>=0;i--){
		inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
	}
	int T;
	cin>>T;
	while(T--){
		int n,k;
		cin>>n>>k;
		int res = (C(n + k / 2 - 1,n) + C(n + k - k / 2 - 1,n)) % mod;
		cout<<res<<'\n';
	}
	return 0;
}
/*
*/
posted @ 2026-08-23 19:29  yutar  阅读(3)  评论(0)    收藏  举报