LuoguP5075 [JSOI2012]分零食
Posted 修电缆的建筑工
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LuoguP5075 [JSOI2012]分零食相关的知识,希望对你有一定的参考价值。
题意
有(A)个人,(m)个糖,你可以选择一个(k),使第(1)~(k)个人每个人至少得到一个糖,并且第(k+1)~(A)个人都得不到糖。(m)个糖必须给完。对于每个方案都有一个欢乐值,欢乐值=(prod_{i=1}^kOx_i^2+Sx_i+U),其中(OSU)都是给定的系数,(x_i)为第(i)个人拿到的糖的数量。求所有方案的欢乐值的和。
这题不用NTT啊......
有个比较naive的(dp):设(f_{i,j})表示前(i)个人一共拿到了(j)个糖的所有方案的欢乐值之和,那么有转移方程:
[ f_{i,j}=sum_{k=1}^{j-i+1}f_{i-1,j-k} imes(Ok^2+Sk+U) ]
初始值可以设(f_{0,0}=1)。这个(dp)的复杂度就是(O(Am^2))。一个优化就是,由于最多前(m)个人拿到糖(每个人至少拿一个糖),所以(i)只用枚举到(min(m,A)),复杂度为(O(m^3))。
观察转移方程的结构,可以发现这样一个优化:
[ f_{i,j-1}=sum_{k=1}^{j-i}f_{i-1,j-1-k} imes(Ok^2+Sk+U)=sum_{k=2}^{j-i+1}f_{i-1,j-k} imes[O(k-1)^2+S(k-1)+U]=sum_{k=2}^{j-i+1}f_{i-1,j-k} imes(Ok^2+Sk+U)- sum_{k=2}^{j-i+1}f_{i-1,j-k} imes(2Ok-O+S) =f_{i,j}-f_{i-1,j-1} imes(O+S+U)- sum_{k=2}^{j-i+1}f_{i-1,j-k} imes(2Ok-O+S) ]
观察最后这个(sum),设(g_{i,j}=sum_{k=1}^{j-i+1}f_{i-1,j-k} imes(2Ok-O+S));那么求(f)的式子可以写成:
[ f_{i,j-1}= f_{i,j}-f_{i-1,j-1} imes(O+S+U)-g_{i,j}+f_{i-1,j-1} imes(O+S)=f_{i,j}-Uf_{i-1,j-1}-g_{i,j} ]
那么(f_{i,j}=f_{i,j-1}+Uf_{i-1,j-1}+g_{i,j})。
(f)的转移变成(O(1))的了。但(g)还是(O(n))的。观察(g)的结构,可以类似地写出求(g)的优化:
[ g_{i,j-1}=sum_{k=1}^{j-i}f_{i-1,j-1-k} imes(2Ok-O+S)=sum_{k=2}^{j-i+1}f_{i-1,j-k} imes[2O(k-1)-O+S]=sum_{k=2}^{j-i+1}f_{i-1,j-k} imes(2Ok-O+S)- sum_{k=2}^{j-i+1}f_{i-1,j-k} imes 2O=g_{i,j}-f_{i-1,j-1} imes(O+S)- sum_{k=2}^{j-i+1}f_{i-1,j-k} imes 2O ]
观察最后这个(sum),设(h_{i,j}=sum_{k=1}^{j-i+1}f_{i-1,j-k} imes 2O);那么求(g)的式子可以写成:
[ g_{i,j-1}= g_{i,j}-f_{i-1,j-1} imes(O+S)-h_{i,j}+f_{i-1,j-1} imes 2O=g_{i,j}-f_{i-1,j-1} imes(S-O)-h_{i,j} ]
那么(g_{i,j}=g_{i,j-1}+f_{i-1,j-1} imes(S-O)+h_{i,j})。
每个(g)也可以(O(1))求了,而且注意到(h)就是前缀和,每个(h)也可以(O(1))求,所以整个(dp)被优化到了(O(m^2))。
可以通过吗?时间上,复杂度虽然是(O(m^2))的,但实际上由于(ileq j),所以只需要循环(frac{m imes(m+1)}{2})次,也就是(5 imes 10^7)级别,是可以过的。空间上,加上滚动数组优化也能过。
#include<bits/stdc++.h>
#define rg register
#define il inline
#define cn const
#define gc getchar()
#define fp(i,a,b) for(rg int i=(a),ed=(b);i<=ed;++i)
using namespace std;
typedef cn int cint;
il int rd(){
rg int x(0),f(1); rg char c(gc);
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=gc; }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=gc;
return x*f;
}
template<typename T> il void ckmin(T &x,cn T &y){ if(x>y)x=y; }
cint maxn=10010;
int A,m,mod,O,S,U,ff,gg,hh,ans;
int f[2][maxn],g[2][maxn],h[2][maxn],pv=0,nw=1;
int main(){
m=rd(),mod=rd(),A=rd(),O=rd(),S=rd(),U=rd();
ff=U,gg=(S-O+mod)%mod,hh=(O<<1)%mod;
f[0][0]=1;
fp(i,1,min(m,A)){
h[nw][i-1]=g[nw][i-1]=f[nw][i-1]=0;
fp(j,i,m){
h[nw][j]=(h[nw][j-1]+hh*f[pv][j-1])%mod;
g[nw][j]=(g[nw][j-1]+gg*f[pv][j-1]+h[nw][j])%mod;
f[nw][j]=(f[nw][j-1]+ff*f[pv][j-1]+g[nw][j])%mod;
}
ans=(ans+f[nw][m])%mod;
nw^=pv^=nw^=pv;
}
printf("%d",ans);
return 0;
}
以上是关于LuoguP5075 [JSOI2012]分零食的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 4332 4332: JSOI2012 分零食 (FFT+快速幂)
bzoj千题计划309:bzoj4332: JSOI2012 分零食(分治FFT)