集训队论文传送门

大概就是我们先用meet in middle求出有恰好k个真甜的方案数
然后我们求这些东西的生成树个数 乘在一起的和就是答案
我们让真甜连真甜 真甜连不甜 假甜连不甜 不甜连不甜 跑一发矩阵树定理
这样只能保证这些真甜的某个子集是真甜 那么我们需要用 0~k-1 的简单容斥一下

// BEGIN CUT HERE
#include<conio.h>
#include<sstream>
// END CUT HERE
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<string>
#include<set>
#include<functional>
#define pb push_back
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<ll,int> abcd;const int N=45;
const int P=1e9+7;ll C[N][N];
inline void Pre(int n){C[0][0]=1;for (int i=1;i<=n;i++){C[i][0]=1;for (int j=1;j<=i;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;}
}inline ll Pow(ll a,int b){ll ret=1;for (;b;b>>=1,a=a*a%P)if (b&1)ret=ret*a%P;return ret;
}
inline ll Inv(ll a){return Pow(a,P-2);
}int a[N][N];
inline int det(int n){int f=0;for (int i=1;i<=n;i++){int k=0;for (int j=i;j<=n;j++) if (a[j][i]) {k=j; break; }if (i^k) { for (int j=i;j<=n;j++) swap(a[i][j],a[k][j]); f^=1; }for (int j=i+1;j<=n;j++){ll t=(ll)Inv(a[i][i])*a[j][i]%P;for (int k=i;k<=n;k++)(a[j][k]+=P-(ll)t*a[i][k]%P)%=P;}}ll ret=1;for (int i=1;i<=n;i++) ret=ret*a[i][i]%P;return f?(P-ret)%P:ret;
}int n,Maxs,val[N];
int S;ll tree[N];
inline void Calc(int k){for (int i=1;i<=n;i++) a[i][i]=0;for (int i=1;i<=n;i++)for (int j=i+1;j<=n;j++)if (!(j>k && j<=S))a[i][j]=a[j][i]=P-1,a[i][i]++,a[j][j]++;elsea[i][j]=a[j][i]=0;tree[k]=det(n-1);for (int i=0;i<k;i++)tree[k]+=P-(ll)C[k][i]*tree[i]%P;tree[k]%=P;
}ll cnt[N];
vector<abcd> lft;
vector<ll> rgt[N];
int pt[N];inline void Count(int n){lft.clear();for (int i=0;i<=n-n/2;i++) rgt[i].clear();for (int i=0;i<(1<<(n/2));i++){int c=0; ll s=0;for (int j=0;j<n/2;j++) if (i>>j&1) c++,s+=val[j+1];lft.pb(abcd(s,c));}sort(lft.begin(),lft.end());for (int i=0;i<(1<<(n-n/2));i++){int c=0; ll s=0;for (int j=0;j<n-n/2;j++) if (i>>j&1) c++,s+=val[n/2+j+1];rgt[c].pb(s);}for (int i=0;i<=n-n/2;i++)sort(rgt[i].begin(),rgt[i].end()),pt[i]=rgt[i].size()-1;for (int i=0;i<=n;i++) cnt[i]=0; for (int i=0;i<(int)lft.size();i++){ll s=lft[i].first; int c=lft[i].second;for (int j=0;j<=n-n/2;j++){while (~pt[j] && s+rgt[j][pt[j]]>Maxs)pt[j]--;cnt[j+c]+=pt[j]+1;}}for (int i=0;i<=n;i++) cnt[i]%=P;
}inline int Solve(){ll ans=0;S=0; Pre(n);for (int i=1;i<=n;i++) if (~val[i]) S++;sort(val+1,val+n+1,greater<int>());for (int k=0;k<=S;k++) Calc(k);Count(S);for (int k=0;k<=S;k++)ans+=cnt[k]*tree[k]%P;return ans%P;
}class SweetFruits{
public:int countTrees(vector <int> sweetness, int maxSweetness){Maxs=maxSweetness; n=sweetness.size();for (int i=1;i<=n;i++) val[i]=sweetness[i-1];return Solve();}// 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(-1);getch() ;return 0;
}
// END CUT HERE

[meet in middle 矩阵树定理 容斥原理] SRM 551 div1 SweetFruits相关推荐

  1. [矩阵树定理 容斥 meet in middle] Topcoder SRM 551 DIV1 Hard. SweetFruits

    枚举最后的树中有多少个是truly sweet的 答案就是 ∑i=0nfi×gi \sum_{i=0}^n f_i\times g_i 其中,fif_i 表示选出 ii 个水果使其价值和不超过Limi ...

  2. Luogu P4336 [SHOI2016]黑暗前的幻想乡(容斥,矩阵树定理,子集反演)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Luogu P4336 [SHOI2016]黑暗前的幻想乡(容斥,矩阵树定理) Problem n≤1 ...

  3. 【学习笔记】矩阵树定理(Matrix-Tree)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 一.矩阵树定理 二.常用定理 三.例题 1. Luogu P6178 [模板]Matrix-Tr ...

  4. 【BZOJ4596】[Shoi2016]黑暗前的幻想乡 容斥+矩阵树定理

    [BZOJ4596][Shoi2016]黑暗前的幻想乡 Description 幽香上台以后,第一项措施就是要修建幻想乡的公路.幻想乡有 N 个城市,之间原来没有任何路.幽香向选民承诺要减税,所以她打 ...

  5. 矩阵树定理2020HDU多校第6场j-Expectation[位运算+期望]

    矩阵树定理 用于求解图上面生成树的个数,生成树的个数等于基尔霍夫矩阵的任何一个N-1阶主子式的行列式的绝对值 矩阵树模板 struct Matrix_Tree {ll a[N][N];Matrix_T ...

  6. 图论数学:矩阵树定理

    运用矩阵树定理进行生成树计数 给定一个n个点m条边的无向图,问生成树有多少种可能 直接套用矩阵树定理计算即可 矩阵树定理的描述如下: 首先读入无向图的邻接矩阵,u-v G[u][v]++ G[v][u ...

  7. [CF917D]Stranger Trees[矩阵树定理+解线性方程组]

    题意 给你 \(n\) 个点的无向完全图,指定一棵树 \(S\),问有多少棵生成树和这棵树的公共边数量为 \(k\in[0,n-1]\) \(n\leq 100\) 分析 考虑矩阵树定理,把对应的树边 ...

  8. HDU多校6 - 6836 Expectation(矩阵树定理+高斯消元求行列式)

    题目链接:点击查看 题目大意:给出一张由 n 个点和 m 条边组成的无向图,对于任意一个生成树,其权值为 n - 1 条边的边权进行二进制的 and 运算,现在需要在图中任意选择一个生成树,问期望权值 ...

  9. Wannafly挑战赛23F-计数【原根,矩阵树定理,拉格朗日插值】

    正题 题目链接:https://ac.nowcoder.com/acm/contest/161/F 题目大意 给出nnn个点的一张图,求它的所有生成树中权值和为kkk的倍数的个数.输出答案对ppp取模 ...

最新文章

  1. 线性代数的本质及其在AI中的应用
  2. 中国社交产品十年记...
  3. php导出excel表格需要隐藏行,php - 隐藏或删除列时PHPExcel导出图像问题 - 堆栈内存溢出...
  4. Qt中的枚举变量,Q_ENUM,Q_FLAG,Q_NAMESPACE,Q_ENUM_NS,Q_FLAG_NS以及其他
  5. 【算法题】Multiples of 3 and 5
  6. 阿里巴巴开源的通用缓存访问框架JetCache介绍
  7. 软件测试 学习之路 计算机基础
  8. linux下VScode开发ESP32,VsCode设置ESP32工具链+刨根问底点灯
  9. Android 系统(200)---Android build.prop参数详解
  10. 练习题︱基于今日头条开源数据的词共现、新热词发现、短语发现
  11. tomcat6.0启动报错
  12. bio linux 创建_[转载]biolinux包含软件
  13. 无线网服务器在哪里设置方法,无线网络如何设置静态ip地址
  14. Python学习笔记哈哈哈
  15. html div与span同行,div和span在一行 div和Span及a标签的区别
  16. mapgis明码文件转为点线面文件_MapGIS明码文件的获得和在坐标转化中的应用研究(2)...
  17. node.js学习笔记3 express基本使用、托管静态资源、express中间件
  18. 全程15分钟 详解如何为MacBook Pro 15寸 加装固态硬
  19. 机器学习/深度学习资源下载合集(持续更新...)
  20. 电机速度rpm转换成轮子的速度

热门文章

  1. [Python黑帽] 三.编程实现IP及端口扫描器、实现多线程C段扫描器
  2. 常用CSS布局(备以查用)
  3. lucene6.0SmartChineseAnalyzer和IK Analyzer比较
  4. 愿面朝大海,春暖花开
  5. java中日期格式的转换_java中定义日期格式的转换符
  6. idea如何配置Android SDK
  7. IDEA安装Android SDK时出现的问题
  8. HTML 中 a 标签的 target=blank 和 target=_blank 的区别
  9. 银行信用卡流失预测模型_基于ANN神经网络_金融培训_论文科研_毕业设计
  10. 【深度学习与图神经网络核心技术实践应用高级研修班-Day1】深度学习的发展历史(完整版)