专栏文章
题解:P8340 [AHOI2022] 山河重整
P8340题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mip3cysr
- 此快照首次捕获于
- 2025/12/03 05:29 3 个月前
- 此快照最后确认于
- 2025/12/03 05:29 3 个月前
My Blogs
P8340 [AHOI2022] 山河重整
题目限制是,对于一种选法 ,要求 。所以有暴力 DP 表示考虑了 的所有数,和是 。复杂度 。
考虑优化,首先两维的状态就爆了。进行容斥, 表示 ,并且 的数全部合法的方案数,答案就是 ,表示钦定 不合法,对第一次不合法的位置进行容斥。
考虑如何求 ,先设 表示 的互异分拆数。考虑把分拆数化成柱形图,一组拆分数 表示为横坐标为 的格子上有一个高度为 的主子。因为是互异的,所以数字个数是 的,也就是柱状图的宽度是 的。枚举最大宽度,因为要求互异,所以比他小的每一种宽度都需要至少有一行,所以从大到小枚举宽度转移 就行了。
再考虑 的转移:, 表示用 的数凑出来 的方案数。
这个不太好算,我们把所有的 放到一起算。这个转移显然有 ,所以进行一个牛顿迭代(?)。假设已经知道了 ,考虑如何推出 。
注意到上面的转移天然可以对最小值进行限制。仍然是从大到小枚举宽度,假设枚举到宽度为 的,可以选择在 中加入一个 的贡献:贡献到 的位置上,表示最小值需要大于等于 ,其余 的转移和 相同,最后 即可。复杂度 。
CPP int n,MOD;
int g[500010],f[500010],h[500010];
const int B=999;
inline void solve(int n)
{
for(int i=0;i<=n;++i)h[i]=0;
for(int i=B;i>=1;--i)
{
for(int j=0;j+i*(j+1)<=n;++j)
Madd(h[j+i*(j+1)],f[j]);
for(int j=n;j>=i;--j)h[j]=h[j-i];
for(int j=0;j<i;++j)h[j]=0;
for(int j=i;j<=n;++j)Madd(h[j],h[j-i]);
}
for(int i=n/2+1;i<=n;++i)f[i]=Cdel(g[i],h[i]);
}
inline void mian()
{
read(n,MOD);
g[0]=1;
for(int i=B;i>=1;--i)
{
for(int j=n;j>=i;--j)g[j]=g[j-i];
for(int j=0;j<i;++j)g[j]=0;
Madd(g[i],1);
for(int j=i;j<=n;++j)Madd(g[j],g[j-i]);
}
int m=2;
f[0]=f[1]=1;
while(m<n)solve(m),m<<=1;
solve(n);
int ans=power(2,n);
for(int i=0;i<n;++i)Mdel(ans,Cmul(f[i],power(2,n-i-1)));
write(ans,'\n');
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...