冲刺NOI2017 (20) 苹果树 (矩阵树定理 容斥原理 Meet in middle)
来源:互联网 发布:DNF数据芯片是干嘛用的 编辑:程序博客网 时间:2024/05/17 06:10
题目大意
给定
现在要用
给定
题解
首先,我们讲生成树上的点分为三种:1.坏点(-1),2.有用的点,3.没用的点。
那么,先不考虑点的标号和权值,得到的生成树应该满足以下几个性质:
- 没用的点只能和坏点连边,
- 有用的点可以和坏点和除自己之外的有用的点连边,
- 坏点可以和任何一个除自己的之外的点连边。
- 有用的点至少和一个其他有用的点连边。
因为考虑最后一个条件的话无法进行构图(或者很难构图),所以我们先只考虑前三个条件进行构图,然后再在后面处理的过程中考虑容斥。
考虑前三个条件:设图中有
然后,对于每一个组合按照上面的规则连边:坏点和所有除自己以外的点连边,有用的点和除自己之外的有用的点连边。然后就可以用矩阵树定理求出这个组合下的生成树个数,记有i个有用的点的图此种生成树的个数为
因为上述的做法没有考虑第四个限制条件,所以我们考虑容斥。说明容斥之前,先明确两个数组的定义:
G[i]: 表示不考虑第四个限制条件,有i 个有用的点时,不同的生成树的个数;F[i]: 表示考虑第四个限制条件,有i 个有用的点时,不同的生成树的个数。
考虑容斥时,在整体中减去不合法的部分。例如,当我们有i个有用的点,且不考虑条件四时,所有这样的生成树中可能有
但是上面的过程没有考虑苹果的权值和标号,那接下来就考虑一下。
对于上面我们处理出来的
考虑枚举,枚举每一个非坏点的苹果是否使用,那么直接就可以处理出数组
因为
最后,
太他娘的奇妙了。
代码:
#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>using namespace std;const int moder=int(1e9)+7;inline int les(const int &a,const int &b) {int c=a-b; return c<0?c+moder:c;}inline int add(const int &a,const int &b) {int c=a+b; return c>=moder?c-moder:c;}inline int mul(const int &a,const int &b) {long long c=1ll*a*b; return c%moder;}inline int fpow(int,int);inline int inv(const int &a) {return fpow(a,moder-2);}int fpow(int a,int k) { register int val=1; for(;k;k>>=1,a=mul(a,a)) if(k&1) val=mul(val,a); return val;}const int maxn=55;int n,lit;int f[maxn][maxn];inline void Add_eage(int x,int y) { if(!f[x][y]) ++f[x][x], ++f[y][y]; f[x][y]=f[y][x]=-1;}//求Kirchhoff矩阵的n-1阶主子式的行列式的绝对值int Gauss(const int n) { register int i,j,k, res=1; for(i=1;i<=n;++i) { if(!f[i][i]) { res=-res; for(j=i+1;j<=n;++j) if(f[j][i]) break; for(k=1;k<=n;++k) swap(f[i][k],f[j][k]); } res=mul(res,f[i][i]); for(j=i+1;j<=n;++j) { int ml=mul(f[j][i],inv(f[i][i])); for(k=i;k<=n;++k) f[j][k]=les(f[j][k],mul(f[i][k],ml)); } } return res;}//构造Kirchhoff矩阵void Construct(const int &x,const int &y,const int &z) { register int i,j; memset(f,0,sizeof f); for(i=x+y+1;i<=n;++i) for(j=1;j<=n;++j) if(i!=j) Add_eage(i,j); for(i=1;i<=x;++i) for(j=1;j<=x;++j) if(i!=j) Add_eage(i,j); return;}int Fact[maxn], Inv[maxn];inline int C(const int &n,const int &m) {return mul(Fact[n],mul(Inv[m],Inv[n-m]));}void Init() { Fact[0]=Inv[0]=1; register int i; for(i=1;i<maxn;++i) Fact[i]=mul(Fact[i-1],i), Inv[i]=inv(Fact[i]); return;}pair<int,int> s1[int(1.5e6)], s2[int(1.5e6)];int top1, top2;int pre[int(1.5e6)][maxn];//Meet in middlevoid MiM(int *w,int n,pair<int,int> *sta,int &top) { register int mask,tmp,num,i; for(mask=0;mask<(1<<n);++mask) { long long sum=0; for(tmp=mask,num=0,i=1;tmp && sum<=lit;tmp>>=1,++i) if(tmp&1 && ~w[i]) sum+=w[i], ++num; if(sum>lit) continue; sta[++top]=make_pair(sum,num); } return;}int c[maxn];int G[maxn], F[maxn];int h[maxn];int main() {#ifndef ONLINE_JUDGE freopen("apple.in","r",stdin); freopen("apple.out","w",stdout);#endif register int i,j; Init(); scanf("%d%d",&n,&lit); for(i=1;i<=n;++i) scanf("%d",&c[i]); sort(c+1,c+1+n); int num=0; while(!~c[num+1]) num++; //预处理G[] for(i=0;i<=n-num;++i) { Construct(i,n-num-i,num); G[i]=Gauss(n-1); } //预处理F[] F[0]=G[0]; for(i=1;i<=n-num;++i) { F[i]=add(F[i],G[i]); for(j=0;j<i;++j) F[i]=les(F[i],mul(F[j],C(i,j))); } int len1=(n-num)>>1, len2=n-num-len1; MiM(c+num,len1,s1,top1); sort(s1+1,s1+1+top1); MiM(c+num+len1,len2,s2,top2); sort(s2+1,s2+1+top2); //处理出前缀和数组 for(i=1;i<=top2;++i) ++pre[i][s2[i].second]; for(j=0;j<=n;++j) for(i=1;i<=top2;++i) pre[i][j]+=pre[i-1][j]; //利用单调性,尺取法统计h[] int p1=1, p2=1; while(p2<=top2 && s1[p1].first+s2[p2].first<=lit) ++p2; --p2; for(p1=1;p1<=top1;++p1) { while(p2 && s1[p1].first>lit-s2[p2].first) --p2; for(i=0;i<=n;++i) h[s1[p1].second+i]=add(h[s1[p1].second+i],pre[p2][i]); } int ans=0; for(i=0;i<=n;++i) ans=add(ans,mul(F[i],h[i])); printf("%d\n",ans); return 0;}
- 冲刺NOI2017 (20) 苹果树 (矩阵树定理 容斥原理 Meet in middle)
- [meet in middle 矩阵树定理 容斥原理] SRM 551 div1 SweetFruits
- Meet in the middle
- bzoj 4596: [Shoi2016]黑暗前的幻想乡 (矩阵树定理+容斥原理)
- [BZOJ4596][Shoi2016]黑暗前的幻想乡(容斥原理+矩阵树定理)
- Codeforces 888E(位运算+meet-in-the-middle)
- bzoj 4596: [Shoi2016]黑暗前的幻想乡 矩阵树定理+容斥原理
- BZOJ 4596: [Shoi2016]黑暗前的幻想乡 矩阵树定理 容斥原理
- 冲刺NOI2017 (20) 距离 (可持久化树链剖分)
- 编程竞赛技巧:Meet in the middle
- [Meet In Middle] HDU 3017 Treasure Division
- [LA2965][建模][Meet in the middle]侏罗纪
- 一道“暴力题” (meet in the middle)
- HDU 5768 (Lucky7 中国剩余定理+容斥原理)
- HDU 5768 Lucky7(中国剩余定理+容斥原理)
- UVa 1326 Jurassic Remains 解题报告(Meet-in-the-Middle)
- codeforces 525E Anya and Cubes(暴力,meet-in-the-middle)
- HDU 6171 Admiral 双向搜索(meet in the middle) + 哈希
- unity3d 5.x standard assets 官方标准资源包下载地址
- sysfs接口函数的建立_DEVICE_ATTR
- 【代码积累】condition of lock
- Http请求中Content-Type讲解以及在Spring MVC中的应用
- Hibernate之Query接口的uniqueResult()方法
- 冲刺NOI2017 (20) 苹果树 (矩阵树定理 容斥原理 Meet in middle)
- JBoss 7.1.1启动时遇到Address already in use: bind /127.0.0.1:9990的处理办法
- keepalived + rsync +inotify-tools实现双机热备
- 定义
- 宕机日记:swap交换分区和并发测试ab工具的使用
- Adb server 进程改造 (一)
- js组建解析json .net组建解析json
- SpringMvc解决跨域问题
- 基于Spring Boot和Spring Cloud实现微服务架构学习