[AGC049D] Convex Sequence

[AGC049D] Convex Sequence

题意

题目写得很清楚。

思路

省流

做原凸包的二阶导数 {ci}\{c_i\},有 k=1nk(k+1)2ck=M\sum_{k=1}^n \frac{k(k+1)}{2} c_k=M

枚举凸包最低点 pp,钦定 pp 一定是最低点最左边的那个点,将 [1,p][1,p] 归入左部,将 [p+1,n][p+1,n] 归入右部。因此左部需要填 p1p-1 个数,其中 cp1c_{p-1} 为正数。右部需要填 npn-p 个数。所有 cic_i 非负。

答案取生成函数的 [xm],[xmn],[x^m],[x^{m-n}],\cdots

可以使用生成函数来做。

第二个条件就是 aiai1ai+1aia_i-a_{i-1} \le a_{i+1}-a_i,即 {ai}\{ a_i \} 是下凸壳。

下凸壳这个要求不好处理。

我们先考虑只有右下凸壳的情况,即斜率非负。

对原数列做差分数组 {bi}\{ b_i \},得到 {bi}\{ b_i \} 单调不减。

然而单调不减依然不好维护,对 {bi}\{ b_i \} 再做差分数组 ci{c_i} ,要求 cic_i 非负。

然而 ci\sum c_i 是未知的,我们只知道 ai=M\sum a_i = M,考虑推出 fici=M\sum f_i c_i = M

M=i=1nai=i=1nj=1ibi=j=1n(nj+1)bj=j=1n(nj+1)k=1jck=k=1n(nk+1)(nk+2)2ck\begin{aligned} M&=\sum_{i=1}^n a_i\\ &=\sum_{i=1}^n \sum_{j=1}^i b_i\\ &=\sum_{j=1}^n (n-j+1) b_j\\ &=\sum_{j=1}^n (n-j+1) \sum_{k=1}^j c_k\\ &=\sum_{k=1}^n \frac{(n-k+1)(n-k+2)}{2} c_k \end{aligned}

换元 k:=nk+1k:=n-k+1

k=1nk(k+1)2ck=M\sum_{k=1}^n \frac{k(k+1)}{2} c_k=M

容易发现 ckc_k00kk 最大到 M\sqrt{M}。思考一下发现这是符合直觉的。而 k>Mk>\sqrt{M}ck=0c_k=0

写出生成函数:

每个 ckc_{k} 可以取值 [0,inf)[0,inf)。对指数的贡献就是 xk(k+1)2×ckx^{\frac{k(k+1)}{2}\times c_k}

[xM]F(x)=k=1min(n,M)11xk(k+1)2[x^M] F(x) = \prod_{k=1}^{\min(n,\sqrt{M})} \frac{1}{1-x^{\frac{k(k+1)}{2}}}

这玩意只关心 MM 项,而且是 M\sqrt{M} 个多项式相乘,考虑递推求解。

定义 t:=k(k+1)2,F(x)n:=k=1n11xtt:=\frac{k(k+1)}{2},F(x)_n := \prod_{k=1}^{n} \frac{1}{1-x^{t}}

F(x)n=11xtF(x)n1F(x)n(1xt)=F(x)n1\begin{aligned} F(x)_n& = \frac{1}{1-x^t} F(x)_{n-1}\\ F(x)_n (1-x^t) &= F(x)_{n-1}\\ \end{aligned}

对于每一项系数 fn1,if_{n-1,i}fn,ifn,it=fn1,if_{n,i} - f_{n,i-t} = f_{n-1,i}

因此得到递推式子 fn,i=fn1,i+fn,itf_{n,i} = f_{n-1,i} + f_{n,i-t}

由于多项式指数为负的系数总是零,因此无需讨论指数为负的情况。

因此可是通过 O(M)O(M) 的时间从 F(x)n1F(x)nF(x)_{n-1} \to F(x)_n

总时间复杂度 O(MM)O(M \sqrt{M})

对于凸壳斜率正负都存在的情况,我们枚举凸壳最低点 pp,左右分开算。

[xM]k=1min(a,M)11xk(k+1)2k=1min(na,M)11xk(k+1)2[x^M] \prod_{k=1}^{\min(a,\sqrt{M})} \frac{1}{1-x^{\frac{k(k+1)}{2}}} \prod_{k=1}^{\min(n-a,\sqrt{M})} \frac{1}{1-x^{\frac{k(k+1)}{2}}}

本质不同的情况只有 O(M)O(\sqrt{M}) 种,而且每次 pp 向右移 11 的时候,相当于式子乘上或者除以 11xk(k+1)2\frac{1}{1-x^{\frac{k(k+1)}{2}}},可以类似上面 O(M)O(M) 递推求出新的多项式。

乘上 11xt\frac{1}{1-x^t}fi=fi+fitf_i' = f_i + f_{i-t}'

除以 11xt\frac{1}{1-x^t}fi=fifitf_i' = f_i - f_{i-t}

然后答案取 xMx_M 的系数。

实现的时候发现不好做,因为一个序列可能拥有多个最低点 pp,因此会算重。

我的做法是钦定 pp 一定是最低点最左边的那个点。将 [1,p][1,p] 归入左部,将 [p+1,n][p+1,n] 归入右部,因此左部需要填 p1p-1 个数,其中 cp1c_{p-1} 非零。右部需要填 npn-p 个数,没有额外限制。

还有一个问题是如果要保证原凸壳的二阶导数非负,就不可以算上最低点位置的二阶导数。因此会造成凸壳整体上移或者下移,二阶导数不变的情况。那么我们可以枚举上移的量,答案加上 [xm],[xmn],[x^m],[x^{m-n}],\cdots

code

注意实际上 kk 的上界为 O(2M)O(\sqrt{2M}),因为有 ckM\iint c_k \le M。大概是这么写的吧。

#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace ababab {
constexpr int N=1e5+7,mod=1e9+7;
int add(int a,int b) { return a+b>=mod ? a+b-mod : a+b; }
void _add(int &a,int b) { a=add(a,b); }
int n,m;
int f[N<<1],_f[N<<1];
int lim;
int laa,lab;
int ans;
void solvemul(int t) {
memcpy(_f,f,sizeof(f));
rep(i,0,m<<1) f[i]=add(_f[i],i-t>=0?f[i-t]:0);
}
void solvediv(int t) {
memcpy(_f,f,sizeof(f));
rep(i,0,m<<1) f[i]=add(_f[i],i-t>=0?mod-_f[i-t]:0);
}
void solvechange(int t) {
memcpy(_f,f,sizeof(f));
rep(i,0,m<<1) f[i]=i+t<=(m<<1)?f[i+t]:0;
}
void solvechange2(int t) {
memcpy(_f,f,sizeof(f));
rep(i,0,m<<1) f[i]=i-t>=0?add(_f[i-t],f[i-t]):0;
}
void main() {
sf("%d%d",&n,&m);
f[0]=1;
lim=ceil(sqrt(m))*2;
lab=lim;
rep(i,1,lim) solvemul(i*(i+1)/2);
rep(a,1,min(n,lim+1)) {
int b=n-a;
int _a=a-1, _b=min(b,lim);
if(laa!=_a) {
rep(k,laa+1,_a) {
solvechange((k-1)*k/2);
solvechange2(k*(k+1)/2);
}
laa=_a;
}
if(lab!=_b) {
rep(k,_b+1,lab) solvediv(k*(k+1)/2);
lab=_b;
}
for(int j=m;j>=0;j-=n) _add(ans,f[j]);
}
pf("%d\n",ans);
}
}
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("my.out","w",stdout);
#endif
ababab :: main();
}
posted @   wing_heart  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示