枚举最后的树中有多少个是truly sweet的
答案就是
∑i=0nfi×gi
其中,
fi
表示选出
i
个水果使其价值和不超过Limit的方案数
设图中前
i
个点是truly sweet,
truly sweet之间两两连边,不甜的水果两两连边,不甜的水果和甜的水果连边
跑矩阵树定理可以得到truly sweet数量之多为
容斥一下就得到了 gi
// BEGIN CUT HERE
// END CUT HERE
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <queue>
#include <assert.h>
#include <cstring>
#define pb push_back
using namespace std;
const int N=105,P=1e9+7;
int n,lim,a[N],f[N],g[N];
vector<int> s,A[N],B[N];
void dfs(int x,int n,int num,int v,vector<int> C[]){
if(v>lim) return ;
if(x>=n) return C[num].pb(v);
dfs(x+1,n,num+1,v+s[x],C);
dfs(x+1,n,num,v,C);
}
int cnt;
inline void part1(){
for(int i=0;i<=n;i++) A[i].clear(),B[i].clear();
dfs(0,cnt/2,0,0,A);
dfs(cnt/2,cnt,0,0,B);
for(int i=0;i<=n;i++) if(A[i].size()) sort(A[i].begin(),A[i].end());
for(int i=0;i<=n;i++) if(B[i].size()) sort(B[i].begin(),B[i].end());
for(int i=0;i<=n;i++){
if(!A[i].size()) continue;
for(int j=0;j<=n;j++){
if(!B[j].size()) continue;
int p=0;
for(int k=B[j].size()-1;~k;k--){
while(p<A[i].size() && A[i][p]+B[j][k]<=lim) p++;
(f[i+j]+=p)%=P;
}
}
}
}
typedef int Mat[N][N];
int inv[N],fac[N];
inline int Pow(int x,int y){
int ret=1;
for(;y;y>>=1,x=1LL*x*x%P) if(y&1) ret=1LL*ret*x%P;
return ret;
}
inline int det(Mat a){
int sp=0;
for(int i=1;i<n;i++){
int p; for(p=i;!a[p][i] && p<n;p++);
if(p==n) return 0;
if(p!=i){
for(int j=1;j<n;j++) swap(a[i][j],a[p][j]);
sp^=1;
}
for(int j=i+1;j<n;j++)
if(a[j][i]){
int t=1LL*a[j][i]*Pow(a[i][i],P-2)%P;
for(int k=1;k<n;k++)
a[j][k]=(a[j][k]+P-1LL*t*a[i][k]%P)%P;
}
}
int ret=1; for(int i=1;i<n;i++) ret=1LL*ret*a[i][i]%P;
if(sp) ret=-ret;
return (ret+P)%P;
}
inline int calc(int x){
static Mat tmp;
memset(tmp,0,sizeof(tmp));
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(i>cnt || j>cnt || (i<=x && j<=x)){
tmp[i][j]=P-1; tmp[j][i]=P-1; tmp[i][i]++; tmp[j][j]++;
}
return det(tmp);
}
inline int C(int x,int y){
return 1LL*fac[x]*inv[y]%P*inv[x-y]%P;
}
inline void part2(){
for(int i=0;i<=cnt;i++) g[i]=calc(i);
for(int i=1;i<=cnt;i++){
for(int j=0;j<i;j++)
g[i]=(g[i]-1LL*C(i,j)*g[j])%P;
g[i]=(g[i]+P)%P;
}
}
inline void Pre(){
fac[0]=1; for(int i=1;i<=n;i++) fac[i]=1LL*fac[i-1]*i%P;
inv[1]=1; for(int i=2;i<=n;i++) inv[i]=1LL*(P-P/i)*inv[P%i]%P;
inv[0]=1; for(int i=1;i<=n;i++) inv[i]=1LL*inv[i]*inv[i-1]%P;
}
class SweetFruits{
public:
int countTrees(vector <int> sweetness, int maxSweetness) {
n=sweetness.size(); lim=maxSweetness; Pre(); s.clear();
for(int i=1;i<=n;i++){
a[i]=sweetness[i-1];
if(a[i]>=0) s.pb(a[i]);
}
cnt=s.size();
memset(f,0,sizeof(f)); memset(g,0,sizeof(g));
part1(); part2(); int ans=0;
for(int i=0;i<=cnt;i++) ans=(ans+1LL*f[i]*g[i])%P;
return ans;
}
// BEGIN CUT HERE
public:
void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); }
private:
template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
void test_case_0() { int Arr0[] = {1, 2, -1, 3}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 3; int Arg2 = 3; verify_case(0, Arg2, countTrees(Arg0, Arg1)); }
void test_case_1() { int Arr0[] = {1, 2, -1, 3}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 5; int Arg2 = 7; verify_case(1, Arg2, countTrees(Arg0, Arg1)); }
void test_case_2() { int Arr0[] = {-1, -1, 2, 5, 5}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 6; int Arg2 = 20; verify_case(2, Arg2, countTrees(Arg0, Arg1)); }
void test_case_3() { int Arr0[] = {2, 6, 8, 4, 1, 10, -1, -1, -1, -1}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 15; int Arg2 = 17024000; verify_case(3, Arg2, countTrees(Arg0, Arg1)); }
void test_case_4() { int Arr0[] = {1078451, -1, 21580110, 8284711, -1, 4202301, 3427559, 8261270, -1, 16176713,
22915672, 24495540, 19236, 5477666, 12280316, 3305896, 17917887, 564911, 22190488, 21843923,
23389728, 14641920, 9590140, 12909561, 20405638, 100184, 23336457, 12780498, 18859535, 23180993,
10278898, 5753075, 21250919, 17563422, 10934412, 22557980, 24895749, 7593671, 10834579, 5606562}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arg1 = 245243285; int Arg2 = 47225123; verify_case(4, Arg2, countTrees(Arg0, Arg1)); }
// END CUT HERE
};
// BEGIN CUT HERE
int main()
{
SweetFruits ___test;
___test.run_test(4);
system("pause");
}
// END CUT HERE