LOJ#6072. 「2017 山东一轮集训 Day5」苹果树 解题报告

好苹果会组成连通块,整棵树的权值为

∑ i = 1 n c i [ c i ≥ 0 ] [ s i z n u m ( c i ) > 1 ] \sum_{i=1}^nc_i[c_i\ge 0][siz_{num(c_i)}>1] i=1∑n​ci​[ci​≥0][siznum(ci​)​>1]

设原树中有 m m m 个好苹果,当有 k k k 个好苹果计入权值(即形成了 s i z > 1 siz>1 siz>1 的连通块), m − k m-k m−k 个好苹果不计入权值(即是孤点),我们求生成树个数。看到生成树我们会想到 Matrix-Tree 定理,不妨试着构造一下。

一个新的 n n n 个点的图,其中 1 ∼ k 1\sim k 1∼k 表示形成连通块的好苹果(PART 1), k + 1 ∼ m k+1\sim m k+1∼m 表示孤点的好苹果(PART 2), m + 1 ∼ n m+1\sim n m+1∼n 表示坏苹果(PART 3)。

连以下几种边:

PART 1 ~ PART 1
PART 1 ~ PART 3
PART 2 ~ PART 3
PART 3 ~ PART 3

我们不能保证 PART 1 的连通块大小都 > 1 > 1 >1,也就是说,求出的答案其实是 ≤ k \le k ≤k 个好苹果形成连通块的 s i z > 1 siz>1 siz>1 的方案,记为 g ( k ) g(k) g(k)。恰好 k k k 个好苹果形成连通块的 s i z > 1 siz>1 siz>1 的方案,记为 f ( k ) f(k) f(k),则

g ( k ) = ∑ i = 0 k ( k i ) f ( i ) g(k)=\sum_{i=0}^k\binom{k}{i}f(i) g(k)=i=0∑k​(ik​)f(i)

二项式反演,得到

f ( k ) = ∑ i = 0 k ( − 1 ) k − i ( k i ) g ( i ) f(k)=\sum_{i=0}^k(-1)^{k-i}\binom{k}{i}g(i) f(k)=i=0∑k​(−1)k−i(ik​)g(i)

于是题目的关键转为如何求计入权值的好苹果数量为 k k k、权值 ≤ l i m \le lim ≤lim 的选点方案数。这个是个经典问题,可以折半搜索+双指针解决。

#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
char In[1000000], *ptrs = In, *ptrt = In;
#define getchar() (ptrs == ptrt && (ptrt = (ptrs = In) + fread(In, 1, 1000000, stdin), ptrs == ptrt) ? EOF : *ptrs++)
ll read() {ll x = 0, f = 1; char ch = getchar();for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');return x * f;
}
const int MAXN = 45, P = 1e9 + 7;
namespace MINT {struct mint {int v;mint(int v = 0) : v(v) {}};int MOD(int v) {return v >= P ? v - P : v;}mint operator + (mint a, mint b) {return MOD(a.v + b.v);}mint operator - (mint a, mint b) {return MOD(a.v - b.v + P);}mint operator * (mint a, mint b) {return 1ll * a.v * b.v % P;}mint qpow(mint a, int n=P-2) {mint ret = 1; for(; n; n >>= 1, a = a * a) if(n & 1) ret = ret * a; return ret;}mint operator += (mint& a, mint b) {return a = a + b;}mint operator -= (mint& a, mint b) {return a = a - b;}mint operator *= (mint& a, mint b) {return a = a * b;}mint operator ++ (mint& a) {return a = a + 1;}mint operator -- (mint& a) {return a = a - 1;}
} using namespace MINT;
int n, m, lim, c[MAXN], a[MAXN];
vector<int> pres[MAXN], sufs[MAXN];
mint h[MAXN];
void calch() {for(int s = 0; s < (1 << (m/2)); s++) {int cnt = 0, sum = 0;for(int i = 0; i < m/2; i++)if((s >> i) & 1) {cnt++; sum += a[i+1];}pres[cnt].push_back(sum);}for(int s = 0; s < (1 << (m-m/2)); s++) {int cnt = 0, sum = 0;for(int i = 0; i < m-m/2; i++)if((s >> i) & 1) {cnt++; sum += a[i+1+m/2];}sufs[cnt].push_back(sum);}for(int i = 0; i <= m/2; i++) {if(pres[i].empty()) continue;sort(pres[i].begin(), pres[i].end());for(int j = 0; j <= m-m/2; j++) {if(sufs[j].empty()) continue;sort(sufs[j].begin(), sufs[j].end());vector<int> &A = pres[i], &B = sufs[j];int q = B.size()-1; mint ans = 0;for(int p = 0; p < (int)A.size() && q >= 0; p++) {while(q >= 0 && A[p] + B[q] > lim) q--;if(q < 0) break;ans += q+1;}h[i+j] += ans;}}
}
mint C[MAXN][MAXN], f[MAXN], g[MAXN];
mint e[MAXN][MAXN];
void addedge(int u, int v) {--u, --v; ++e[u][u]; ++e[v][v]; --e[u][v]; --e[v][u];}//delete the line 1.
mint det(mint a[][MAXN], int n) {int f = 0;for(int i = 1; i <= n; i++) {int num = -1;for(int j = i; j <= n; j++)if(a[j][i].v) { num = j; break; }if(num == -1) return 0;if(i != num) {f ^= 1;for(int j = i; j <= n; j++) swap(a[i][j], a[num][j]);}mint in = qpow(a[i][i]);for(int j = i+1; j <= n; j++) {mint t = in * a[j][i];for(int k = i; k <= n; k++) a[j][k] -= a[i][k] * t;}}mint ans = 1; for(int i = 1; i <= n; i++) ans *= a[i][i];if(f) ans = 0-ans;return ans;
}
mint calcg(int k) {for(int i = 1; i <= n-1; i++)for(int j = 1; j <= n-1; j++)e[i][j] = 0;for(int i = 1; i <= k; i++) {for(int j = i+1; j <= k; j++) addedge(i, j);for(int j = m+1; j <= n; j++) addedge(i, j);}for(int i = k+1; i <= m; i++)for(int j = m+1; j <= n; j++)addedge(i, j);for(int i = m+1; i <= n; i++)for(int j = i+1; j <= n; j++) addedge(i, j);return det(e, n-1);
}
int main() {n = read(), lim = read();for(int i = 1; i <= n; i++) {c[i] = read();if(c[i] != -1) a[++m] = c[i];}calch();for(int i = 0; i <= m; i++) g[i] = calcg(i);C[0][0] = 1;for(int i = 1; i <= m; i++) {C[i][0] = 1;for(int j = 1; j <= i; j++) C[i][j] = C[i-1][j-1] + C[i-1][j];}for(int i = 0; i <= m; i++) {f[i] = 0;for(int j = 0; j <= i; j++)if((i - j) & 1) f[i] -= C[i][j] * g[j];else f[i] += C[i][j] * g[j];}mint ans = 0;for(int i = 0; i <= m; i++) ans += h[i] * f[i];printf("%d\n", ans.v);return 0;
}

LOJ#6072. 「2017 山东一轮集训 Day5」苹果树 解题报告相关推荐

  1. Loj #6077. 「2017 山东一轮集训 Day7」逆序对

    Loj #6077. 「2017 山东一轮集训 Day7」逆序对 Solution 令fi,jf_{i,j}fi,j​表示前iii个数产生jjj个逆序对的方案数,每次考虑把i+1i+1i+1加入,有i ...

  2. LOJ#6074. 「2017 山东一轮集训 Day6」子序列

    LOJ#6074. 「2017 山东一轮集训 Day6」子序列 先考虑全局询问怎么做,设 f ( i , c ) f(i,c) f(i,c) 表示在 S 1 ⋯ i S_{1\cdots i} S1⋯ ...

  3. LOJ#6103. 「2017 山东二轮集训 Day2」第一题 解题报告

    LOJ#6103. 「2017 山东二轮集训 Day2」第一题 解题报告 前置知识:闭区间上的连续函数的零点存在性定理: 我们定义这样的函数: 定义域为 [ l , r ] ∩ Z [l,r]\cap ...

  4. #6073. 「2017 山东一轮集训 Day5」距离(树链剖分 + 永久标记主席树)

    #6073. 「2017 山东一轮集训 Day5」距离 给定一颗有nnn个节点带边权的树,以及一个排列ppp,path(u,v)path(u, v)path(u,v)为u,vu, vu,v路径上的点集 ...

  5. [LOJ#6068]. 「2017 山东一轮集训 Day4」棋盘[费用流]

    题意 题目链接 分析 考虑每个棋子对对应的横向纵向的极大区间的影响:记之前这个区间中的点数为 \(x\) ,那么此次多配对的数量即 \(x\) . 考虑费用流,\(S\rightarrow 横向区间 ...

  6. loj#6100. 「2017 山东二轮集训 Day1」第一题 主席树+二分

    题目描述: 小火车沉迷垃圾手游不能自拔,正在玩碧蓝航线,可惜小火车的舰(lao)队(po)练度太低打不过副本,所以他只好去刷其余的副本来升级. 总共有 n 个副本编号从 1 到 n ,每个副本有个难度 ...

  7. loj #6070. 「2017 山东一轮集训 Day4」基因

    回文自动机好题啊! 解法一 每$\sqrt n \(分一块 每块建回文自动机到字符串末尾. 顺便开三个\)\sqrt n * n\(的数组记下预处理答案,回文自动机头指针,和每个节点第一次出现的右端点 ...

  8. 「2017 山东一轮集训 Day5」距离

    /* 写完开店再写这个题目顿时神清气爽, 腰也不疼了, 眼也不花了首先考虑将询问拆开, 就是查询一些到根的链和点k的关系根据我们开店的结论, 一个点集到一个定点的距离和可以分三部分算 那么就很简单了吧 ...

  9. 容斥问卷调查反馈——Co-prime,Character Encoding,Tree and Constraints,「2017 山东一轮集训 Day7」逆序对

    文章目录 Co-prime source solution code Character Encoding source solution code Tree and Constraints sour ...

最新文章

  1. 「深度」线下大数据正成为构建精准“用户画像”的最大助力
  2. 异常处理汇总-后端系列
  3. C#开发ActiveX网页截图控件
  4. Python-OpenCV 处理图像(六)(七)(八):对象识别 图像灰度化处理 图像二值化处理
  5. 求最大公约数的设计与C语言实现
  6. python实例[判断操作系统类型]
  7. 基础的shell编程问题(一)
  8. linux7配置dns服务器,centOS7搭建DNS服务器配置详解
  9. 头顶距离顶部百分比_近距离接触COLMO子母太空舱洗衣机:“真分区洗”应该什么样...
  10. 输入5个整数,找出5个数中的两位数
  11. 计算机网络学习方法和书籍推荐
  12. 好的架构不是设计出来的,而是演进出来的
  13. 【新书速递】计算机系统解密:从理解计算机到编写高效代码
  14. 耦合器滤波器衰减器无源器件自动化测试软件系统,纳米NSAT-1000
  15. 第九届蓝桥杯大赛个人赛决赛(CB软件类)真题
  16. windows下软件安装:Anaconda下安装Pymol
  17. 混合动力simulink模型 转卖新能源混动车型模式转换说明,包含HCU模式转换simulink框图及说明文档
  18. 过压保护芯片,高输入电压(OVP)
  19. 洛克希德·马丁公司的创新灵魂 和 波音的“鬼怪工厂”
  20. 2021 46届icpc 南京

热门文章

  1. 计算机在交通规划中的应用,浅谈计算机在交通运输行业中的应用
  2. 美检方不予起诉刘强东,性侵案正式结案
  3. 咖啡制作培训:黑芝麻生椰拿铁详细教程
  4. element 表格合并单元格之后数据选择问题
  5. [徐州.12.4的一次会议]:知识图谱
  6. 华为荣耀9能升级鸿蒙,华为鸿蒙OS全面来袭!百款华为/荣耀手机可升级:一个系统就能满足...
  7. ElasticSearch关闭重启命令
  8. 阿里巴巴和腾讯考虑相互开放!
  9. html怎么设计上标,css如何显示文字的上标和下标
  10. 王者荣耀服务器维护被扣分,王者荣耀出现大范围维护事故,无数玩家躺枪被扣分,直接被禁赛!...