51nod 1446

来源:互联网 发布:ai cc for mac破解版 编辑:程序博客网 时间:2024/06/03 20:35

一个good点如果只和bad相连就不计算他的价值,否则算入总价值记作great点,要求总价值<=maxval

这些good点之间除了权值没啥区别,生成树计数容易想到用矩阵树定理去统计,但是用矩阵树定理,只能通过让他们之和bad间有边限制i个点一定不是great点,对于其他点有可能还有不是great点的情况统计
于是用g[i]表示至少i个good点非great,f[i]表示恰好i个good点非great,用减掉恰好j(j>i)个good点非great的情况,考虑我们固定了1~i非great,共m个good点,剩下j-i个非great点在m-i个里面有Cjimi种情况,每种对应一个f[j],有f[i]=g[i]mj=i+1Cjimif[j]

值非常大不能dp,所以统计sum<=maxval的great情况貌似NPC?
要2^n枚举,直接枚举不能接受,考虑折半,枚举哪些点是great,i个great点的情况枚举出来后排序,然后meet in middle

复杂度O(n4+2n/2nlogn)

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;const int maxn = 42;const int Mod  = 1e9+7;inline void add(int &x,const int &y){x+=y;if(x>=Mod)x-=Mod;}inline void dec(int &x,const int &y){x-=y;if(x<0)x+=Mod;}int pw(int x,int k){    if(x<0) x+=Mod;    int re=1;    for(;k;k>>=1,x=(ll)x*x%Mod) if(k&1)        re=(ll)re*x%Mod;    return re;}int inv(int x){return pw(x,Mod-2);}int n,m,N,val;int c[maxn][maxn],v[maxn];struct matrix{int a[maxn];}a[maxn];void Gauss(){    for(int i=1;i<N;i++)    {        if(a[i].a[i]==0)        {            int flag=-1;            for(int j=i+1;j<N;j++) if(a[j].a[i]) { flag=j;break; }            if(flag!=-1) for(int j=1;j<N;j++) swap(a[i].a[j],a[flag].a[j]);        }        if(a[i].a[i]==0) return;        int cc=inv(a[i].a[i]);        for(int j=i+1;j<N;j++) if(a[j].a[i])        {            int div=(ll)cc*a[j].a[i]%Mod;            for(int k=i;k<N;k++) dec(a[j].a[k],(ll)a[i].a[k]*div%Mod);        }    }}int g[maxn],f[maxn];void cal(const int k){    for(int i=1;i<=N;i++) memset(a[i].a,0,sizeof a[i].a);    for(int i=1;i<=k;i++)    {        for(int j=1;j<=n;j++)        {            int id=m+j;            a[i].a[i]++,a[id].a[id]++;            a[i].a[id]--,a[id].a[i]--;        }    }    for(int i=k+1;i<N;i++)    {        for(int j=i+1;j<=N;j++)        {            a[i].a[i]++,a[j].a[j]++;            a[i].a[j]--,a[j].a[i]--;        }    }    for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) dec(a[i].a[j],0);    Gauss();    g[k]=1;    for(int i=1;i<N;i++) g[k]=(ll)g[k]*a[i].a[i]%Mod;}vector<int>V1[maxn],V2[maxn];void search(){    int mid=N>>1;    int al=1<<mid;    for(int i=0;i<=mid;i++) V1[i].clear();    for(int i=0;i<al;i++)    {        int num=0,sum=0;        for(int j=1;j<=mid;j++) if(i>>j-1&1)        {            if(v[j]==-1) { num=-1; break; }            num++,sum+=v[j];        }        if(num!=-1) V1[num].push_back(sum);    }    for(int i=0;i<=mid;i++) sort(V1[i].begin(),V1[i].end());    al=1<<N-mid;    for(int i=0;i<=N-mid;i++) V2[i].clear();    for(int i=0;i<al;i++)    {        int num=0,sum=0;        for(int j=1;j<=N-mid;j++) if(i>>j-1&1)        {            if(v[mid+j]==-1) { num=-1; break; }            num++,sum+=v[mid+j];        }        if(num!=-1) V2[num].push_back(sum);    }    for(int i=0;i<=N-mid;i++) sort(V2[i].begin(),V2[i].end());}struct node{int i,j,x;};inline bool operator <(const node x,const node y){return x.x<y.x;}priority_queue<node>q;int match[maxn];int main(){    c[0][0]=1;    for(int i=1;i<maxn;i++)    {        c[i][0]=1;        for(int j=1;j<maxn;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%Mod;    }    int tcase; scanf("%d",&tcase);    while(tcase--)    {        scanf("%d%d",&n,&val);        for(int i=1;i<=n;i++) scanf("%d",&v[i]);        N=n;        m=0; for(int i=1;i<=n;i++) if(v[i]!=-1) m++;        n=N-m;        for(int i=0;i<=m;i++) cal(i);        for(int i=m;i>=0;i--)         {            f[i]=g[i];            for(int j=i+1;j<=m;j++)                dec(f[i],(ll)f[j]*c[m-i][j-i]%Mod);        }        search();        int mid=N>>1; int re=0;        for(int i=0;i<=mid;i++)        {            memset(match,0,sizeof match);            while(!q.empty()) q.pop();            for(int j=0;j<=N-mid;j++) if(V2[j].size())                 q.push((node){j,V2[j].size()-1,V2[j][V2[j].size()-1]}),match[j]=V2[j].size();            for(int j=0;j<V1[i].size();j++)            {                int cc=V1[i][j];                if(q.empty()) break;                while(!q.empty())                {                    node now=q.top(); if(cc+now.x<=val) break;                    q.pop();                    for(;now.j>=0&&V2[now.i][now.j]+cc>val;now.j--) match[now.i]--;                    if(now.j<0) continue;                    now.x=V2[now.i][now.j];                    q.push(now);                }                for(int l=0;l<=N-mid;l++) if(match[l])                    add(re,(ll)match[l]*f[m-(i+l)]%Mod);            }        }        printf("%d\n",re);    }    return 0;}