Solution -「SV 2020 Round I」「SRM 551 DIV1」「TC 12141」SweetFruits
\(\mathcal{Description}\)
link.
给定 \(n\) 个水果,每个结点可能有甜度 \(v_i\),或不甜(\(v_i=-1\))。现在把这些水果串成一棵无根树。称一个水果“真甜”,当且仅当其本身和至少一个邻接水果是甜的。每个“真甜”水果对树的甜度产生 \(v_i\) 的贡献。求所有甜度不超过 \(maxv\) 的树。
\(n\le40\)。
\(\mathcal{Solution}\)
令无序地取恰好 \(i\) 个水果使其甜度和不超过 \(maxv\) 的方案数为 \(f_i\),树上恰有 \(i\) 个“真甜”果的方案数为 \(g_i\)。显然答案为 \(\sum f_ig_i\)。
\(\mathcal{Part~1}\)
求 \(f_i\)。
这是一个经典(我已经忘记)的 \(\text{meet in the middle}\) 问题。先取出甜水果全集,任意分成等大(或大小差 \(1\))的两部分。分别枚举两部分的子集,统计其甜度和及子集大小,并分别按甜度和为关键字升序排列,构成两个序列,令为 \(A,B\)。接下来用一个 \(\text{two-pointers}\) 的技巧。从小到大枚举 \(B\) 中的元素,注意到其甜度不减,所以可与其配对的 \(A\) 的元素范围逐渐向左减小。每次维护 \(A\) 中新的右端点,在暴力枚举在 \(A\) 中取的集合大小统计与 \(B\) 当前元素构成的方案数。(不像人话 qwq,看代码吧。)
这部分复杂度 \(\mathcal O(2^{\frac{n}2}n)\)。
\(\mathcal{Part~2}\)
求 \(g_i\)。
直接算出每个 \(g_i\) 貌似有些困难。我们先算出树上有不超过 \(i\) 个“真甜”果的方案数。设共有甜果 \(m\) 个,“真甜”果 \(k\) 个。不妨令“真甜”果为 \(1,2,\dots,k\),甜而非“真甜”(就叫它们清甜 w)果为 \(k+1,k+2,\dots,m\),不甜果为 \(m+1,m+2,\dots,n\)。想象一个完全图,删除所有“甜-清甜”与“清甜-清甜”的连边,用 \(\text{Matrix-Tree}\) 求出生成树个数。可以发现,这样的一棵生成树不可能让“清甜”变成“真甜”,所以这就是不超过 \(i\) 个“真甜”果的方案数。此时,再利用此前计算出的 \(g\) 减去多出来的一些方案即可。
这部分复杂度 \(\mathcal O(n^4)\),故总复杂度 \(\mathcal O(2^{\frac{n}2}n+n^4)\)。
\(\mathcal{Code}\)
#include <cstdio>
#include <vector>
#include <algorithm>
const int MAXN = 40, MOD = 1e9 + 7;
int n, val[MAXN + 5], maxv, inv[MAXN + 5], fac[MAXN + 5], ifac[MAXN + 5];
int chose[MAXN + 5], mayswt[MAXN + 5];
std::vector<int> swt;
std::vector<std::pair<int, int> > swtsum[2];
inline int qkpow ( int a, int b, const int p = MOD ) {
int ret = 1;
for ( ; b; a = 1ll * a * a % p, b >>= 1 ) ret = 1ll * ret * ( b & 1 ? a : 1 ) % p;
return ret;
}
struct MatrixTree {
int K[MAXN + 5][MAXN + 5];
inline void clear () {
for ( int i = 1; i <= n; ++ i ) {
for ( int j = 1; j <= n; ++ j ) {
K[i][j] = 0;
}
}
}
inline void add ( const int u, const int v ) {
++ K[u][u], ++ K[v][v], -- K[u][v], -- K[v][u];
if ( K[u][v] < 0 ) K[u][v] += MOD;
if ( K[v][u] < 0 ) K[v][u] += MOD;
}
inline int det () {
int ret = 1, swp = 1;
for ( int i = 1; i < n; ++ i ) {
for ( int j = i; j < n; ++ j ) {
if ( K[j][i] ) {
if ( i ^ j ) std::swap ( K[i], K[j] ), swp *= -1;
break;
}
}
if ( ! ( ret = 1ll * ret * K[i][i] % MOD ) ) return 0;
int inv = qkpow ( K[i][i], MOD - 2 );
for ( int j = i + 1; j < n; ++ j ) {
int d = 1ll * K[j][i] * inv % MOD;
for ( int k = i; k < n; ++ k ) {
K[j][k] = ( K[j][k] - 1ll * d * K[i][k] % MOD + MOD ) % MOD;
}
}
}
return ( ret * swp + MOD ) % MOD;
}
} mt;
inline void init () {
inv[1] = fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
for ( int i = 2; i <= n; ++ i ) {
inv[i] = 1ll * ( MOD - MOD / i ) * inv[MOD % i] % MOD;
fac[i] = 1ll * i * fac[i - 1] % MOD;
ifac[i] = 1ll * inv[i] * ifac[i - 1] % MOD;
}
}
inline int comb ( const int n, const int m ) {
return n < m ? 0 : 1ll * fac[n] * ifac[m] % MOD * ifac[n - m] % MOD;
}
inline void calcSwt () {
int lef = swt.size () >> 1, rig = swt.size () - lef;
for ( int s = 0; s < 1 << lef; ++ s ) {
int bit = 0, sval = 0;
for ( int i = 0; i < lef; ++ i ) {
if ( ( s >> i ) & 1 ) {
++ bit, sval += swt[i];
}
}
if ( sval <= maxv ) swtsum[0].push_back ( std::make_pair ( sval, bit ) );
}
for ( int s = 0; s < 1 << rig; ++ s ) {
int bit = 0, sval = 0;
for ( int i = 0; i < rig; ++ i ) {
if ( ( s >> i ) & 1 ) {
++ bit, sval += swt[lef + i];
}
}
if ( sval <= maxv ) swtsum[1].push_back ( std::make_pair ( sval, bit ) );
}
std::sort ( swtsum[0].begin (), swtsum[0].end () );
std::sort ( swtsum[1].begin (), swtsum[1].end () );
int cnt[45] {};
for ( int i = 0; i ^ swtsum[0].size (); ++ i ) ++ cnt[swtsum[0][i].second];
for ( int i = 0, j = int ( swtsum[0].size () ) - 1; i ^ swtsum[1].size (); ++ i ) {
for ( ; ~ j && swtsum[1][i].first + swtsum[0][j].first > maxv; -- cnt[swtsum[0][j --].second] );
for ( int k = 0; k <= lef; ++ k ) {
chose[k + swtsum[1][i].second] = ( chose[k + swtsum[1][i].second] + cnt[k] ) % MOD;
}
}
}
class SweetFruits {
public:
inline int countTrees ( std::vector<int> tval, const int tmaxv ) {
n = tval.size (), init ();
for ( int i = 1; i <= n; ++ i ) val[i] = tval[i - 1];
maxv = tmaxv;
for ( int i = 1; i <= n; ++ i ) if ( ~ val[i] ) swt.push_back ( val[i] );
calcSwt ();
for ( int i = 0; i <= ( int ) swt.size (); ++ i ) {
mt.clear ();
for ( int u = 1; u <= n; ++ u ) {
for ( int v = u + 1; v <= n; ++ v ) {
if ( v <= i || ( int ) swt.size () < v ) {
mt.add ( u, v );
}
}
}
mayswt[i] = mt.det ();
for ( int j = 1; j < i - 1; ++ j ) {
mayswt[i] = ( mayswt[i] - 1ll * comb ( i, j ) * mayswt[i - j] % MOD + MOD ) % MOD;
}
if ( i ) mayswt[i] = ( mayswt[i] - mayswt[0] + MOD ) % MOD;
}
int ans = 0;
for ( int i = 0; i <= ( int ) swt.size (); ++ i ) if ( i ^ 1 ) ans = ( ans + 1ll * mayswt[i] * chose[i] ) % MOD;
return ans;
}
};
Solution -「SV 2020 Round I」「SRM 551 DIV1」「TC 12141」SweetFruits的更多相关文章
- Solution -「SV 2020 Round I」SA
\(\mathcal{Description}\) 求出处 owo. 给定一个长度为 \(n\),仅包含小写字母的字符串 \(s\),问是否存在长度为 \(n\),仅包含小写字母的字符串 \( ...
- 「LibreOJ NOI Round #2」不等关系
「LibreOJ NOI Round #2」不等关系 解题思路 令 \(F(k)\) 为恰好有 \(k\) 个大于号不满足的答案,\(G(k)\) 表示钦点了 \(k\) 个大于号不满足,剩下随便填的 ...
- LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿
二次联通门 : LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿 /* LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿 dp 记录一下前驱 ...
- 「NOIP 2020」微信步数(计数)
「NOIP 2020」微信步数(Luogu P7116) 题意: 有一个 \(k\) 维场地,第 \(i\) 维宽为 \(w_i\),即第 \(i\) 维的合法坐标为 \(1, 2, \cdots, ...
- 转:Android开源项目推荐之「网络请求哪家强」 Android开源项目推荐之「网络请求哪家强」
转载自https://zhuanlan.zhihu.com/p/21879931 1. 原则 本篇说的网络请求专指 http 请求,在选择一个框架之前,我个人有个习惯,就是我喜欢选择专注的库,其实在软 ...
- [Q&A]VS 2012 MVC4专案与网站的差异?「ASP.NET组态」的Login账号出现在「新旧两组」会员数据库里面?
原文出處 http://www.dotblogs.com.tw/mis2000lab/archive/2013/08/30/mvc4_vs2012_login_member_db.aspx [Q&a ...
- Solution -「ZJOI 2020」「洛谷 P6631」序列
\(\mathcal{Description}\) Link. 给定一个长为 \(n\) 的非负整数序列 \(\lang a_n\rang\),你可以进行如下操作: 取 \([l,r]\),将 ...
- Solution -「JOISC 2020」「UOJ #509」迷路的猫
\(\mathcal{Decription}\) Link. 这是一道通信题. 给定一个 \(n\) 个点 \(m\) 条边的连通无向图与两个限制 \(A,B\). 程序 Anthon ...
- Solution -「NOI 2020」「洛谷 P6776」超现实树
\(\mathcal{Description}\) Link. 对于非空二叉树 \(T\),定义 \(\operatorname{grow}(T)\) 为所有能通过若干次"替换 \( ...
随机推荐
- git报错 error: cannot stat 'file': Permission denied
切换分支(git checkout xxx)时报错: error: cannot stat 'file': Permission denied 解决方法:退出编辑器.浏览器.资源管理器等,然后再切换就 ...
- react中state与setstate的使用
我们可以利用state来定义一些变量的初始值 //放在construcor里 this.state = { list: [1, 2, 3] } 要更改state里的值,注意要遵循react里immut ...
- Vue系列教程(三)之vue-cli脚手架的使用
一.Vue-cli的环境准备 目的:(1)快速管理依赖 (2)确定项目结构 1.安装node.js Node.js是一个可以让前端运行在服务器上的一个工. 下载:https://nodejs.org/ ...
- WebLogic任意文件上传漏洞(CVE-2019-2725)
一,漏洞介绍 1.1漏洞简介 Oracle weblogic反序列化远程命令执行漏洞,是根据weblogic的xmldecoder反序列化漏洞,只是通过构造巧妙的利用链可以对Oracle官方历年来针对 ...
- HDURomantic
Problem - 1004 (hdu.edu.cn) 扩展欧几里得解决线性同余方程.先得到gcd的解,再恢复原解,因为知道通解的一般形式,所以通过模来得到最小正整数解.另一个可以通过相减,或者一样的 ...
- netty系列之:一口多用,使用同一端口运行不同协议
目录 简介 SocksPortUnificationServerHandler 自定义PortUnificationServerHandler 总结 简介 在之前的文章中,我们介绍了在同一个netty ...
- Android开发 海康威视 多路视频播放(同时播放视频)
原文地址:Android开发 海康视频 多路视频播放 | Stars-One的杂货小窝 最近公司有个项目需要对接到海康监控摄像头来实现对应的实时播放和回放,但这两个不是我们今天要讨论的重点,APP首页 ...
- gin框架中的同步异步
goroutine机制可以方便地实现异步处理 另外,在启动新的goroutine时,不应该使用原始上下文,必须使用它的只读副本 // 异步 func longAsync(context *gin.Co ...
- 操作系统的发展史(并发与并行)<异步与同步>《进程与程序》[非堵塞与堵塞]
目录 一:一:手工操作 -- 穿孔卡片 1.简介 二:手工操作方式两个特点: 三:批处理 -- 磁带存储 1.联机批处理系统 2.脱机批处理系统 3.多道程序系统 4.多道批处理系统 四:总结发展史 ...
- 业务驱动的全景监控体系在阿里的应用 | 阿里巴巴DevOps实践指南
编者按:本文源自阿里云云效团队出品的<阿里巴巴DevOps实践指南>,扫描上方二维码或前往:https://developer.aliyun.com/topic/devops,下载完整版电 ...