51Nod1446 限制价值树
讲课时候一点儿都没懂
分成两个部分:
找到所有满足sum<=mx的集合,即枚举哪些是great的、统计每个great的集合对应多少个树
发现,第二个部分只和great集合大小有关
具体的
第一个部分:折半爆搜+sort+双指针,得到g[i]大小为i的great集合个数
第二部分:
f[i]表示钦定i个是great的生成树个数
答案=∑f[i]*g[i]
求f[i]?
不妨钦定1~i为great
完全图,把所有连接至少一个good的边去掉,矩阵树定理求生成树
这样得到了至多有i个great的个数h
减去孤立的:
则f[i]=h-∑0<=j<i,f[j]*C(i,j)
即可。
#include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^'0') #define pb push_back #define solid const auto & #define enter cout<<endl #define pii pair<int,int> using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');} namespace Miracle{ const int N=44; const int mod=1e9+7; const int M=(1<<20)+233; int n,mx,m; int C[N][N]; int ad(int x,int y){ return x+y>=mod?x+y-mod:x+y; } int mul(int x,int y){ return (ll)x*y%mod; } int qm(int x,int y){ int ret=1; while(y){ if(y&1) ret=(ll)ret*x%mod; x=(ll)x*x%mod; y>>=1; } return ret; } int val[N]; int pre[(1<<20)+233][21]; struct po{ int s,sz; po(){} po(int ss,int size){s=ss;sz=size;} bool friend operator <(po a,po b){ return a.s<b.s; } }p[2][M]; int cnt[2]; void dfs(int x,int lim,int lp,int sz,int sum){ if(sum>mx) return; if(x==lim+1){ ++cnt[lp]; p[lp][cnt[lp]]=po(sum,sz);return; } if(val[x]<0) dfs(x+1,lim,lp,sz,sum); else{ dfs(x+1,lim,lp,sz,sum); dfs(x+1,lim,lp,sz+1,sum+val[x]); } } int t[N][N]; int guass(int f[N][N],int n){ // cout<<" guass "<<endl; // for(reg i=1;i<=n;++i){ // prt(f[i],1,n); // }cout<<endl; int tmp=1; for(reg i=1;i<=n;++i){ int id=0; for(reg j=i;j<=n;++j){ if(f[j][i]) { id=j;break; } } if(id==0) return 0; if(id!=i){ tmp=-tmp; for(reg j=1;j<=n;++j) swap(f[i][j],f[id][j]); } int inv=qm(f[i][i],mod-2); for(reg j=i+1;j<=n;++j){ if(f[j][i]){ int c=mul(f[j][i],inv); for(reg k=i;k<=n;++k){ f[j][k]=ad(f[j][k],mod-mul(c,f[i][k])); } } } } ll ret=ad(mod,tmp); for(reg i=1;i<=n;++i) ret=mul(ret,f[i][i]);return ret; } int g[N],f[N]; void clear(){ memset(g,0,sizeof g); memset(f,0,sizeof f); memset(pre,0,sizeof pre); cnt[0]=cnt[1]=0; m=0; } int main(){ int T;rd(T); C[0][0]=1; for(reg i=1;i<=42;++i){ C[i][0]=1; for(reg j=1;j<=i;++j){ C[i][j]=ad(C[i-1][j],C[i-1][j-1]); } } while(T--){ rd(n);rd(mx); for(reg i=1;i<=n;++i) { rd(val[i]); if(val[i]>=0) ++m; } int half=n/2; dfs(1,half,0,0,0); sort(p[0]+1,p[0]+cnt[0]+1); for(reg i=1;i<=cnt[0];++i){ memcpy(pre[i],pre[i-1],sizeof pre[i-1]); pre[i][p[0][i].sz]++; } dfs(half+1,n,1,0,0); sort(p[1]+1,p[1]+cnt[1]+1); int ptr=cnt[0]; for(reg i=1;i<=cnt[1];++i){ while(ptr>0&&p[1][i].s+p[0][ptr].s>mx) --ptr; for(reg j=0;j<=half;++j){ g[j+p[1][i].sz]=ad(g[j+p[1][i].sz],pre[ptr][j]); } } for(reg i=0;i<=m;++i){ memset(t,0,sizeof t); for(reg j=1;j<=i;++j){t[j][j]=i-1+n-m;} for(reg j=i+1;j<=m;++j){t[j][j]=n-m;} for(reg j=m+1;j<=n;++j){t[j][j]=n-1;} for(reg j=1;j<=n;++j){ for(reg k=1;k<=n;++k){ if(j==k) continue; if(j<=i&&i<k&&k<=m) continue; if(i<j&&j<=m&&k<=i) continue; if(i<k&&k<=m&&i<j&&j<=m) continue; // cout<<" add "<<j<<" "<<k<<endl; t[j][k]=ad(t[j][k],mod-1); } } f[i]=guass(t,n-1); // cout<<" st "<<f[i]<<endl; for(reg j=0;j<i;++j){ f[i]=ad(f[i],mod-mul(C[i][j],f[j])); } } ll ans=0; // prt(g,0,m); // prt(f,0,m); for(reg i=0;i<=m;++i){ ans=ad(ans,mul(g[i],f[i])); } printf("%lld\n",ans); if(T) clear(); } } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* */