[AGC049D] Convex Sequence
[AGC049D] Convex Sequence
题意
题目写得很清楚。
思路
省流
做原凸包的二阶导数 \(\{c_i\}\),有 \(\sum_{k=1}^n \frac{k(k+1)}{2} c_k=M\)。
枚举凸包最低点 \(p\),钦定 \(p\) 一定是最低点最左边的那个点,将 \([1,p]\) 归入左部,将 \([p+1,n]\) 归入右部。因此左部需要填 \(p-1\) 个数,其中 \(c_{p-1}\) 为正数。右部需要填 \(n-p\) 个数。所有 \(c_i\) 非负。
答案取生成函数的 \([x^m],[x^{m-n}],\cdots\)。
可以使用生成函数来做。
第二个条件就是 \(a_i-a_{i-1} \le a_{i+1}-a_i\),即 \(\{ a_i \}\) 是下凸壳。
下凸壳这个要求不好处理。
我们先考虑只有右下凸壳的情况,即斜率非负。
对原数列做差分数组 \(\{ b_i \}\),得到 \(\{ b_i \}\) 单调不减。
然而单调不减依然不好维护,对 \(\{ b_i \}\) 再做差分数组 ${c_i} $,要求 \(c_i\) 非负。
然而 \(\sum c_i\) 是未知的,我们只知道 \(\sum a_i = M\),考虑推出 \(\sum f_i c_i = M\)。
换元 \(k:=n-k+1\)。
容易发现 \(c_k\) 非 \(0\) 的 \(k\) 最大到 \(\sqrt{M}\)。思考一下发现这是符合直觉的。而 \(k>\sqrt{M}\) 的 \(c_k=0\)。
写出生成函数:
每个 \(c_{k}\) 可以取值 \([0,inf)\)。对指数的贡献就是 \(x^{\frac{k(k+1)}{2}\times c_k}\)
这玩意只关心 \(M\) 项,而且是 \(\sqrt{M}\) 个多项式相乘,考虑递推求解。
定义 \(t:=\frac{k(k+1)}{2},F(x)_n := \prod_{k=1}^{n} \frac{1}{1-x^{t}}\)。
对于每一项系数 \(f_{n-1,i}\) 有 \(f_{n,i} - f_{n,i-t} = f_{n-1,i}\)。
因此得到递推式子 \(f_{n,i} = f_{n-1,i} + f_{n,i-t}\)。
由于多项式指数为负的系数总是零,因此无需讨论指数为负的情况。
因此可是通过 \(O(M)\) 的时间从 \(F(x)_{n-1} \to F(x)_n\)。
总时间复杂度 \(O(M \sqrt{M})\)。
对于凸壳斜率正负都存在的情况,我们枚举凸壳最低点 \(p\),左右分开算。
本质不同的情况只有 \(O(\sqrt{M})\) 种,而且每次 \(p\) 向右移 \(1\) 的时候,相当于式子乘上或者除以 \(\frac{1}{1-x^{\frac{k(k+1)}{2}}}\),可以类似上面 \(O(M)\) 递推求出新的多项式。
乘上 \(\frac{1}{1-x^t}\):\(f_i' = f_i + f_{i-t}'\)。
除以 \(\frac{1}{1-x^t}\):\(f_i' = f_i - f_{i-t}\)。
然后答案取 \(x_M\) 的系数。
实现的时候发现不好做,因为一个序列可能拥有多个最低点 \(p\),因此会算重。
我的做法是钦定 \(p\) 一定是最低点最左边的那个点。将 \([1,p]\) 归入左部,将 \([p+1,n]\) 归入右部,因此左部需要填 \(p-1\) 个数,其中 \(c_{p-1}\) 非零。右部需要填 \(n-p\) 个数,没有额外限制。
还有一个问题是如果要保证原凸壳的二阶导数非负,就不可以算上最低点位置的二阶导数。因此会造成凸壳整体上移或者下移,二阶导数不变的情况。那么我们可以枚举上移的量,答案加上 \([x^m],[x^{m-n}],\cdots\)。
code
注意实际上 \(k\) 的上界为 \(O(\sqrt{2M})\),因为有 \(\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();
}
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18607302