题目链接
题意
求长度为 n、满足以下条件的整数序列 A 的个数:
- ∀i∈[1,n),Ai≤Ai+1;
- ∀k∈[1,n),任意 k 个 A 中的数之和都严格小于任意 k+1 个 A 中的数之和。
思路
易知第二个条件只要对于 k=⌊2n−1⌋ 满足即可。
设序列 A 的差分数组为 d,其中 d0=1。
根据题目要求易得:
- ∀i∈[1,n],di≥0;
- ∑i=1k+1Ai>∑i=n−k+1nAi;
- ∑i=0ndi=An≤n,即 ∑i=1ndi<n。
由第二个限制得:
A1d1+1d1>i=1∑k(An−k+i−Ai+1)>i=3∑n−k(i−2)⋅di+i=n−k+1∑n(n−i+1)⋅di≥i=3∑n−k(i−2)⋅di+i=n−k+1∑n(n−i+1)⋅di
把第三个限制的 d1 提出得:
d1<n−i=2∑ndi
此时我们便得出了 d1 的取值范围(与个数):
∣{d1}∣=(n−i=2∑ndi)−(i=3∑n−k(i−2)⋅di+i=n−k+1∑n(n−i+1)⋅di)=n−(d2+i=3∑n−k(i−1)⋅di+i=n−k+1∑n(n−i+2)⋅di)
问题转为,对于每种 d2,d3,…,dn,求和 ∣{d1}∣。
令 wi 为 di 的系数,即 w={0,1,2,3,…,n−k−1,k+1,k,…,2}。
以 w 为重量,2∼n 的物体数量无限,做一次完全背包,最后计算出的 fi 即为括号内总和为 i 的 d2,d3,…,dn 个数。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include<cstdio> using namespace std; const int N=5000; int n,k,p; int w[N+1]; int f[N]; int res; int main() { scanf("%d%d",&n,&p); k=(n-1)/2; w[2]=1; for(int i=3;i<=n-k;++i) { w[i]=i-1; } for(int i=n-k+1;i<=n;++i) { w[i]=n-i+2; } f[0]=1; for(int i=2;i<=n;++i) { for(int j=0;j+w[i]<n;++j) { f[j+w[i]]=(f[j+w[i]]+f[j])%p; } } for(int i=0;i<n;++i) { res=(res+1ll*(n-i)*f[i])%p; } printf("%d\n",res); return 0; }
|