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+快速幂)

bzoj4332[JSOI2012]分零食

JSOI2012 分零食 生成函数 FFT

bzoj千题计划309:bzoj4332: JSOI2012 分零食(分治FFT)

[luoguP2858] [USACO06FEB]奶牛零食Treats for the Cows(DP)

[LuoguP1197][JSOI2008]星球大战