agc041d

agc041d Problem Scores

题目链接

题目大意

给出数列长度 N N N ( N ≤ 5000 N \leq 5000 N5000)与质数 M M M ( M ≤ 1 0 9 M\le 10^9 M109) 输出满足以下三个条件的数列的数目
∀ i ∈ [ 1 , n ) , a i ≤ a i + 1 \forall i \in [1,n) ,a_i \leq a_{i+1} i[1,n),aiai+1

∀ i ∈ [ 1 , n ] , 1 ≤ a i ≤ n \forall i \in [1,n],1 \leq a_i \leq n i[1,n],1ain

∀ k ∈ [ 1 , n ) , ∑ i = 1 k + 1 a i > ∑ i = n − k + 1 n a i \forall k \in [1,n),\sum_{i=1}^{k+1} a_i > \sum_{i=n-k+1}^{n} a_i k[1,n),i=1k+1ai>i=nk+1nai

思路

条件一可以简述为数列单调不降

条件二可以通过条件一化简为 a 1 ≥ 1 a_1 \ge 1 a11 a n ≤ n a_n \le n ann

条件三较为复杂,对其进行分析

当前 k + 1 k+1 k+1 个数与后 k k k 个数重叠时,考虑去掉重叠的数,可以转化为不重叠的情况

因此条件三只需要考虑 ∀ k ∈ [ 1 , ⌊ n − 1 2 ⌋ ] \forall k \in [1,\lfloor \frac {n-1}{2} \rfloor ] k[1,2n1] 的情况即可

观察该区间内的不等式,发现若对于 k = x k=x k=x 不等式成立,则对于 k = x − 1 k=x-1 k=x1 不等式依旧成立

因为 k k k x x x x − 1 x-1 x1 ,相当于不等号左边减掉一个较小的数,右边减掉一个较大的数,所以依旧成立

因此,如果对于 k = ⌊ n − 1 2 ⌋ k=\lfloor \frac {n-1}{2} \rfloor k=2n1 有不等式成立,则对于 ∀ k ∈ [ 1 , ⌊ n − 1 2 ⌋ ] \forall k \in [1,\lfloor \frac {n-1}{2} \rfloor ] k[1,2n1] ,不等式均成立

现给出条件四
k = ⌊ n − 1 2 ⌋ , ∑ i = 1 k + 1 a i > ∑ i = n − k + 1 n a i k=\lfloor \frac {n-1}{2} \rfloor,\sum_{i=1}^{k+1} a_i > \sum_{i=n-k+1}^{n} a_i k=2n1,i=1k+1ai>i=nk+1nai
综上,条件四与条件三等价

一般来说,统计方案数可以考虑按位从左到右dp,下标需要记录

另外,条件一的单调不降需要记录当前位的 a i a_i ai 的值

而条件四需要记录之前所有 a i a_i ai 的和

这样就至少需要记三维的状态了,但 n n n 有五千,显然不能直接dp

考虑通过差分去掉单调性

单调不降表示 a i + 1 ≥ a i a_{i+1}\ge a_i ai+1ai 也即 a i + 1 − a i ≥ 0 a_{i+1}-a_i\ge 0 ai+1ai0 ,于是令 d i = a i − a i − 1 d_i=a_i-a_{i-1} di=aiai1 (先将 a 0 a_0 a0 视为 0 0 0 )

发现由于 a 1 ≥ 1 a_1\ge 1 a11 , d 1 d_1 d1 的限制有些另类,方便起见,还是将 a 0 a_0 a0 视为 1 1 1

于是有 a i = a 0 + ∑ j = 1 i d j = 1 + ∑ j = 1 i d j a_i=a_0+\sum_{j=1}^{i}d_j=1+\sum_{j=1}^{i}d_j ai=a0+j=1idj=1+j=1idj

将上式代入条件一,二,四,并化简得到新的三个条件
∀ i ∈ [ 1 , n ] , d i ≥ 0 \forall i \in [1,n] , d_i \ge 0 i[1,n],di0

∑ i = 1 n d i ≤ n − 1 \sum_{i=1}^{n}d_i \le n-1 i=1ndin1

∑ j = 1 n d j c j ≤ 0 c j = { j − 2 1 ≤ j ≤ ⌊ n 2 ⌋ + 1 n − j + 1 ⌊ n 2 ⌋ + 1 < j ≤ n \sum_{j=1}^{n} d_j c_j \le 0 \\ c_j=\left\{ \begin{array}{rcl} j-2 & & {1\le j \le \lfloor \frac{n}{2}\rfloor +1}\\ n-j+1 & & {\lfloor \frac{n}{2}\rfloor +1 < j \le n}\\ \end{array} \right. j=1ndjcj0cj={j2nj+11j2n+12n+1<jn

那么问题转化为统计合法的数列 d d d 的个数

发现条件二和条件三还是要记两个状态,不能直接做

观察 c j c_j cj,发现先递增,后递减,并且除了 c 1 = − 1 < 0 c_1=-1<0 c1=1<0,其他的 c j c_j cj 都非负,只有第一位最特殊

于是考虑提出 d 1 d_1 d1

首先 d 1 ≥ 0 d_1 \ge 0 d10 是肯定的

将条件二中的 d 1 d_1 d1 提出得
d 1 ≤ n − 1 − ∑ i = 2 n d i d_1\le n-1-\sum_{i=2}^{n} d_i d1n1i=2ndi
将条件三中的 d 1 d_1 d1 提出得
d 1 ≥ ∑ j = 2 n d j c j d_1\ge \sum_{j=2}^{n} d_j c_j d1j=2ndjcj
发现这两个条件恰好就是 d 1 d_1 d1 的上下限,于是合起来就是
0 ≤ ∑ j = 2 n d j c j ≤ d 1 ≤ n − 1 − ∑ i = 2 n d i 0\le \sum_{j=2}^{n} d_j c_j \le d_1 \le n-1-\sum_{i=2}^{n} d_i 0j=2ndjcjd1n1i=2ndi
所以 d 1 d_1 d1 可以取 [ ∑ j = 2 n d j c j , n − 1 − ∑ j = 2 n d j ] [\sum_{j=2}^{n} d_j c_j,n-1-\sum_{j=2}^{n} d_j] [j=2ndjcj,n1j=2ndj] 中的任意值

综上,当其他 d i d_i di 都确定下来后, d 1 d_1 d1 m a x ( n − ∑ j = 2 n d j ( 1 + c j ) , 0 ) max(n-\sum_{j=2}^{n}d_j(1+c_j),0) max(nj=2ndj(1+cj),0) 种取值

然后数列就可以分成 d 1 d_1 d1 d 2 . . d n d_2..d_n d2..dn 两段来考虑了

考虑枚举后面那段的权值和 i = ∑ j = 2 n d j ( 1 + c j ) i=\sum_{j=2}^{n}d_j(1+c_j) i=j=2ndj(1+cj)

易得,先考虑后面那段的合法方案 ,再考虑 d 1 d_1 d1 的取值就可以正确地算出总方案数

(对后面那段的限制只有 d i ≥ 0 d_i \ge 0 di0 ,其他所有限制都在 d 1 d_1 d1 的取值里考虑进去了)

f i f_i fi i = ∑ j = 2 n d j ( 1 + c j ) i=\sum_{j=2}^{n}d_j(1+c_j) i=j=2ndj(1+cj) 的方案数

于是答案为 ∑ i = 0 n f i ∗ m a x ( n − i , 0 ) = ∑ i = 0 n f i ( n − i ) \sum_{i=0}^{n}f_i*max(n-i,0)=\sum_{i=0}^{n}f_i(n-i) i=0nfimax(ni,0)=i=0nfi(ni)

问题转化为求 f i f_i fi

d p [ i ] [ j ] dp[i][j] dp[i][j] 表示后只考虑 d i . . d n d_i..d_n di..dn 的情况下, j = ∑ k = i n d k ( 1 + c k ) j=\sum_{k=i}^{n}d_k(1+c_k) j=k=indk(1+ck) 的方案数

于是 d p [ 2 ] [ 1.. n ] dp[2][1..n] dp[2][1..n] 即为 f [ 1 ] . . f [ n ] f[1]..f[n] f[1]..f[n]

大力转移即可,第一维可以滚动,也可以像完全背包那样优化掉

复杂度 O ( n 2 ) O(n^2) O(n2)

代码

#include <bits/stdc++.h>
using namespace std;
int dp[5005],c[5005];
int n,MOD,ans;
int main()
{
    cin>>n>>MOD;
    for (int i=1;i<=n;++i) if (i<=n/2+1) c[i]=i-2; else c[i]=n-i+1;
    dp[0]=1;
    for (int i=n;i>1;--i)
        for (int j=c[i]+1;j<=n;++j)
            (dp[j]+=dp[j-c[i]-1])%=MOD;
    for (int i=0;i<=n;++i) ans=(1LL*dp[i]*(n-i)+ans)%MOD;
    cout<<ans<<endl;
    return 0;
}
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值