2017多校訓練賽第一場 HDU 6042 (母函式)
Journey with Knapsack
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 164 Accepted Submission(s): 61
Problem Description
KazaQ has a knapsack with volume 2⋅n
and n
kinds of food, where the i-th
food's volume is i
and the number of it is ai
(1≤i≤n
KazaQ plans to make a journey but after that he needs to store some food and one piece of equipment into the knapsack. He has
m
Assuming that two plans are distinct if and only if they contain different pieces of equipment or there exists at least one integer
k
(1≤k≤n)
satisfying the number of the k
The answer may be very large, so you only need to give the value of the answer modulo
109+7.
Input
The input contains multiple test cases.
For each test case:
The first line contains two positive integers n
and m,
satisfying 1≤n≤5⋅104,1≤m≤2⋅n.
The second line contains n
distinct non-negative integers a1,a2,⋯,an,
satisfying 0≤a1<a2<⋯<an≤2⋅n.
The third line contains m
positive integers b1,b2,⋯,bm,
satisfying 1≤b1,b2,⋯,bm≤2⋅n.
About 100
test cases in total, where no more than 5
cases satisfy n≥103.
Output
For each test case, output "Case #x:
y"
in one line (without quotes), where x
indicates the case number starting from 1
and y
denotes the answer of corresponding case.
Sample Input
1 1 1 1 2 2 1 2 3 4 3 3 1 2 3 2 3 3Sample Output
Case #1: 1 Case #2: 2 Case #3: 6Source
人生第一道母函式的題目,紀念一下……
我就稍微說說母函式吧。母函式分為普通型母函式和指數型母函式,兩個分別對應解決組合問題和排列問題。關於它的用法表示,這個自己看看百度百科吧,個人感覺百科已經說得很清楚了。大致意思就是可以通過母函式某一次項的係數來確定結果。
然後這題的話,總共有n個物品,第i個物品的體積為i,數量為ai。那麼物品i對應的母函式就是1+x^i+x^2i+x^3i+……+x^ai。剩下的直接就看官方題解吧,夠清楚了……
如果你覺得亂,我也沒辦法,感覺這題真的得靠自己理解……具體見程式碼:
#include<bits/stdc++.h>
#define mod 1000000007
#define LL long long
#define N 200010
using namespace std;
LL dp[N],f[N];
int n,m;
int main()
{
int T_T=0; dp[0]=1;
for(int i=1;i<=100000;i++) //預處理五邊形數
{
for(int j=1,k=1;k<=i;k+=3*j+1,j++)
{
if (j&1) dp[i]+=dp[i-k]; else dp[i]-=dp[i-k];
dp[i]=(dp[i]%mod+mod)%mod;
}
for(int j=1,k=2;k<=i;k+=3*j+2,j++)
{
if (j&1) dp[i]+=dp[i-k]; else dp[i]-=dp[i-k];
dp[i]=(dp[i]%mod+mod)%mod;
}
}
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<=2*n;i++)
f[i]=dp[i];
for(int i=1;i<=n;i++)
{
int x; scanf("%d",&x);
if ((LL)(x+1)*i<=2*n)
for(int j=2*n;j>=(x+1)*i;j--) //類似揹包dp的方法減去第一部分
{
f[j]-=f[j-(x+1)*i];
f[j]=(f[j]%mod+mod)%mod;
}
}
for(int i=1,s=1;i<=2*n;i++) //字首和的方式減去這一部分
{
f[i+n]-=s; s+=f[i];
f[i+n]=(f[i+n]%mod+mod)%mod;
if (s>=mod) s%=mod;
}
LL ans=0;
for(int i=1;i<=m;i++) //再嘗試放不同的equipment來統計結果
{
int x; scanf("%d",&x);
ans+=f[2*n-x];
if (ans>=mod) ans%=mod;
}
printf("Case #%d: %I64d\n",++T_T,ans);
}
return 0;
}