題目大意
Rosemary有一個容積爲2n的揹包,還有n種物品,第i種物品的容積爲i,有ai個,保證a是非負整數且遞增(即
現在lihua擺出了m個裝備幫助Rosemary完成他的旅行,第i個裝備的容積爲bi,Rosemary必須選擇恰好一個裝備以及若干個物品裝進揹包去旅行,要求揹包裝滿,問有多少種方案。
兩種方案不同,當且僅當選擇的裝備不同,或者某種物品的選擇數量不同。
n<=5*10^4。對10^9+7取模。
生成函數
不妨設選擇物品的生成函數爲
那麼
對於第
即
則
我們分開兩部分考慮。
第一部分
注意到
那麼
因爲我們的多項式要在模
不妨先算出其餘部分,最後把這根號個單項乘上去,那麼複雜度爲
第二部分
我們希望計算
我們探討發現這個式子的意義其實是把一個數拆分成一些<=n的正整數之和的本質不同方案數。
這樣不好做,我們進行一些轉化。以下均默認在模
設
則前面部分就是
現在的意義是把一個數拆分成任意一些正整數之和的本質不同方案數,即拆分數的計算。
拆分數
計算拆分數有一個經典做法。
即五邊形數定理。
證明請研究http://blog.csdn.net/visit_world/article/details/52734860
根據該式子可以在
#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);
}
}