[hdu6042]Journey with Knapsack

版权声明:本文是蒟蒻写出来的,神犇转载也要说一声哦! https://blog.csdn.net/WerKeyTom_FTD/article/details/79032280

题目大意

Rosemary有一个容积为2n的背包,还有n种物品,第i种物品的容积为i,有ai个,保证a是非负整数且递增(即ai>=0ai<ai+1)。
现在lihua摆出了m个装备帮助Rosemary完成他的旅行,第i个装备的容积为bi,Rosemary必须选择恰好一个装备以及若干个物品装进背包去旅行,要求背包装满,问有多少种方案。
两种方案不同,当且仅当选择的装备不同,或者某种物品的选择数量不同。
n<=5*10^4。对10^9+7取模。

生成函数

不妨设选择物品的生成函数为F(x)
那么ans=mi=1[x2nbi]F(x)
对于第i种物品,其生成函数为1+xi+x2i++xaii
1x(ai+1)i1xi
F(x)=ni=1(1x(ai+1)i)ni=111xi
我们分开两部分考虑。

第一部分

注意到ai>=0ai<ai+1,这意味着ai>=i1
那么(ai+1)i>=i2
因为我们的多项式要在模x2n+1意义下计算,因此可以发现只有前根号个有用。
不妨先算出其余部分,最后把这根号个单项乘上去,那么复杂度为O(nn)

第二部分

我们希望计算ni=111xix2n+1
我们探讨发现这个式子的意义其实是把一个数拆分成一些<=n的正整数之和的本质不同方案数。
这样不好做,我们进行一些转化。以下均默认在模x2n+1意义下进行。
ni=111xi
=2ni=111xi2ni=n+1(1xi)
=2ni=111xi(12ni=n+1xi)
P(x)=ni=111xixn
则前面部分就是P(x)。后面部分很容易处理。
现在的意义是把一个数拆分成任意一些正整数之和的本质不同方案数,即拆分数的计算。

拆分数

计算拆分数有一个经典做法。
即五边形数定理。
p(n)=k>=1(1)k+1[p(nk(3k+1)2)+p(nk(3k1)2)]
证明请研究http://blog.csdn.net/visit_world/article/details/52734860
根据该式子可以在O(nn)的时间内预处理拆分数。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=50000+10,mo=1000000007;
int f[maxn*2],g[maxn*2],h[maxn*2],a[maxn];
int i,j,k,l,r,t,n,m,ans,ca;
int main(){
    while (scanf("%d%d",&n,&m)!=EOF){
        ca++;
        fo(i,1,n) scanf("%d",&a[i]);
        g[0]=1;
        fo(i,1,2*n){
            g[i]=0;
            fo(k,1,n){
                if (k%2) r=1;else r=-1;
                t=k*(3*k-1)/2;
                if (t>i) break;
                (g[i]+=g[i-t]*r)%=mo;
                t=k*(3*k+1)/2;
                if (t>i) continue;
                (g[i]+=g[i-t]*r)%=mo;
            }
        }
        fo(k,1,n){
            t=(a[k]+1)*k;
            if (t>2*n) break;
            fd(i,2*n,t) (g[i]-=g[i-t])%=mo;
        }
        fo(i,0,2*n) h[i]=0;
        fo(i,0,n-1) (h[i+n+1]-=g[i])%=mo;
        fo(i,1,2*n) (h[i]+=h[i-1])%=mo;
        fo(i,0,2*n) f[i]=(g[i]+h[i])%mo;
        ans=0;
        fo(i,1,m){
            scanf("%d",&t);
            (ans+=f[2*n-t])%=mo;
        }
        (ans+=mo)%=mo;
        printf("Case #%d: %d\n",ca,ans);
    }
}
阅读更多
想对作者说点什么?
相关热词

博主推荐

换一批

没有更多推荐了,返回首页