CF961G Partitions 组合数学

本文探讨了一个复杂的组合数学问题,即如何计算将n个带权物品分成k个集合的所有可能方式的权值总和,通过巧妙的数学转换和分析,提供了一种O(nlogn)的高效解决方案。

Description


有n个带权物品,要把它们分成k个集合
定义一个分法的权值为每个集合的大小*集合内权值之和
问所有分法权值之和

Solution


一开始没看到要乘上一个集合大小。。以为是sb题
讲一个头铁娃的做法

显然每个物品对答案贡献的系数都是一样的。考虑枚举一个物品所在集合的大小s,那么有
∑s=1ns(n−1s−1){n−sk−1}\sum_{s=1}^{n}{s\binom{n-1}{s-1}\begin{Bmatrix}n-s\\k-1\end{Bmatrix}}s=1ns(s1n1){nsk1}
这个柿子还是很直观的
跳过一些中间拆掉斯特林数和交换枚举的步骤,我们不难得到这样一个柿子
∑i=0k−1(−1)i(k−i−1)!i!∑s=1ns(n−1s−1)(k−i−1)n−s\sum_{i=0}^{k-1}{\frac{{\left(-1\right)}^{i}}{{\left(k-i-1\right)}!{i}!}\sum_{s=1}^{n}{s\binom{n-1}{s-1}{\left(k-i-1\right)}^{n-s}}}i=0k1(ki1)!i!(1)is=1ns(s1n1)(ki1)ns
我们不妨分析后面那个Σ的内容
找不同环节到了。。一个神仙操作就是
∑s=1ns(n−1s−1)(k−i−1)n−s=∑s=1n(s−1)(n−1s−1)(k−i−1)n−s+∑s=1n(n−1s−1)(k−i−1)n−s\sum_{s=1}^{n}{s\binom{n-1}{s-1}{\left(k-i-1\right)}^{n-s}}=\sum_{s=1}^{n}{\left(s-1\right)\binom{n-1}{s-1}{\left(k-i-1\right)}^{n-s}}+\sum_{s=1}^{n}{\binom{n-1}{s-1}{\left(k-i-1\right)}^{n-s}}s=1ns(s1n1)(ki1)ns=s=1n(s1)(s1n1)(ki1)ns+s=1n(s1n1)(ki1)ns
注意到k(nk)=n(n−1k−1)k\binom{n}{k}=n\binom{n-1}{k-1}k(kn)=n(k1n1),于是
(n−1)∑s=1n(n−2s−2)(k−i−1)n−s+∑s=1n(n−1s−1)(k−i−1)n−s\left(n-1\right)\sum_{s=1}^{n}{\binom{n-2}{s-2}{\left(k-i-1\right)}^{n-s}+\sum_{s=1}^{n}{\binom{n-1}{s-1}{\left(k-i-1\right)}^{n-s}}}(n1)s=1n(s2n2)(ki1)ns+s=1n(s1n1)(ki1)ns
又注意到kn=(k−1+1)n=∑i=0n(ni)(k−1)n−ik^n={\left(k-1+1\right)}^n=\sum_{i=0}^{n}{\binom{n}{i}{\left(k-1\right)^{n-i}}}kn=(k1+1)n=i=0n(in)(k1)ni,所以我们可以把上面的柿子化成
(n−1)(k−i)n−2+(k−i)n−1\left(n-1\right){\left(k-i\right)}^{n-2}+{\left(k-i\right)}^{n-1}(n1)(ki)n2+(ki)n1
然后往回带,就可以做到O(nlog⁡n)O(n\log n)O(nlogn)求系数了,最后乘上权值之和就是答案
累死我了。。

Code


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>

#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
#define copy(x,t) memcpy(x,t,sizeof(x))

#define fi first
#define se second

typedef std:: pair <int,int> pair;
typedef long double ld;
typedef long long LL;

const int INF=0x3f3f3f3f;
const int MOD=1e9+7;
const int ny2=(MOD+1)/2;
const int N=200005;
const ld pi=acos(-1);
const ld e=exp(1);
const ld eps=1e-8;

LL inv[N],fac[N],w[N];

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

LL ksm(LL x,LL dep) {
	LL res=1;
	for (;dep;dep>>=1,x=x*x%MOD) {
		(dep&1)?(res=res*x%MOD):0;
	}
	return res;
}

int main(void) {
	int n=read(),k=read();
	LL sum=0,T=0;
	fac[0]=fac[1]=inv[0]=inv[1]=1;
	rep(i,2,n-1) {
		fac[i]=fac[i-1]*i%MOD;
		inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
	}
	rep(i,2,n-1) inv[i]=inv[i-1]*inv[i]%MOD;
	rep(i,1,n) {
		LL tmp=read();
		sum+=tmp; (sum>=MOD)?(sum-=MOD):0;
	}
	if (n==1) return 0&printf("%lld\n", sum);
	rep(i,0,k-1) {
		LL tmp=inv[i]*inv[k-i-1]%MOD*ksm(k-i,n-2)%MOD*(n+k-i-1)%MOD;
		if (i&1) T+=MOD-tmp;
		else T+=tmp;
		(T>=MOD)?(T-=MOD):0;
	}
	printf("%lld\n", sum*T%MOD);
	return 0;
}
<think>我们之前讨论的是PostgreSQL中分区表的问题,用户提到“pgsql表里面没有partitions这个模块”,并再次强调“我想解决pgsql表中缺少partitions模块的问题”。结合之前的回答和用户当前的问题,我们需要明确以下几点: 1. 用户可能在PostgreSQL中尝试查询分区信息时遇到了问题,比如系统表中没有名为`partitions`的表或视图。 2. 实际上,在PostgreSQL中,分区信息存储在系统目录中,但并没有一个名为`partitions`的独立表。分区信息可以通过其他系统视图和函数来获取。 回顾之前的回答,我们已经提到: - 在PostgreSQL 10及以上版本,分区表功能是内置的,分区信息可以通过`pg_catalog.pg_partitioned_table`、`pg_catalog.pg_inherits`等系统视图查询。 - 使用`pg_partition_tree`函数(PostgreSQL 12+)可以查看分区树。 用户当前的困惑可能是:他们期望有一个名为`partitions`的表(类似Hive Metastore中的`PARTITIONS`表)来直接查看分区信息,但PostgreSQL没有这样的表。 因此,解决思路是: 1. 解释PostgreSQL中分区信息的存储方式。 2. 提供查询分区信息的正确方法。 3. 根据用户使用的PostgreSQL版本给出具体查询示例。 同时,参考用户提供的引用[2]中的SQL语句(这是一个Hive Metastore查询,连接了多个表来获取表的分区信息),用户可能习惯于Hive中查询分区的方式,而PostgreSQL的实现不同。 具体解决方法: ### 1. **确认PostgreSQL版本** - 运行`SELECT version();`查看版本。如果版本低于10,则分区功能有限(使用继承表模拟),需要升级。 ### 2. **查询分区信息的正确方法** - **PostgreSQL 10及以上版本**: - **查看所有分区表**: ```sql SELECT * FROM pg_catalog.pg_partitioned_table; ``` 此视图存储分区表的分区键等信息。 - **查看特定表的分区**: 通过`pg_inherits`系统视图和`pg_class`关联查询: ```sql SELECT c.relname AS partition_name FROM pg_inherits i JOIN pg_class c ON i.inhrelid = c.oid JOIN pg_class p ON i.inhparent = p.oid WHERE p.relname = 'your_table_name'; ``` 或者使用PostgreSQL 12+的`pg_partition_tree`函数: ```sql SELECT * FROM pg_partition_tree('your_table_name'); ``` - **如果使用继承表(PostgreSQL 10之前)**: 在旧版本中,分区通常手动通过继承实现。查询继承关系(即分区): ```sql SELECT c.relname AS child_table FROM pg_inherits i JOIN pg_class c ON i.inhrelid = c.oid WHERE i.inhparent = 'parent_table'::regclass; ``` ### 3. **自定义视图(模拟`partitions`表)** 如果用户希望有一个类似Hive中`PARTITIONS`表的视图,可以创建自定义视图(假设PostgreSQL 10+): ```sql CREATE VIEW partitions AS SELECT pg_parent.relname AS table_name, pg_child.relname AS partition_name, pg_get_expr(pg_child.relpartbound, pg_child.oid) AS partition_definition FROM pg_inherits JOIN pg_class pg_parent ON pg_inherits.inhparent = pg_parent.oid JOIN pg_class pg_child ON pg_inherits.inhrelid = pg_child.oid JOIN pg_namespace ON pg_parent.relnamespace = pg_namespace.oid WHERE pg_parent.relkind = 'p'; -- 只包含分区表 ``` 然后查询: ```sql SELECT * FROM partitions WHERE table_name = 'your_table'; ``` ### 4. **注意事项** - **权限问题**:确保当前用户有权限访问系统视图(通常需要超级用户或特定授权)。 - **分区表标识**:在PostgreSQL中,分区表有`relkind='p'`(主表)和`relkind='r'`(分区子表),通过`pg_class`可查。 ### 总结 用户问题核心是**在PostgreSQL中没有名为`partitions`的系统表**,但可以通过查询系统视图(如`pg_inherits`、`pg_class`)或使用内置函数(如`pg_partition_tree`)获取分区信息。建议根据实际版本选择查询方式,或创建自定义视图满足需求。 如果用户仍遇到问题,请提供具体错误信息或查询示例。 §§相关问题§§ 1. 如何在PostgreSQL 14中创建分区表? 2. PostgreSQL中如何动态管理分区(如自动创建新分区)? 3. 如何查询分区表的存储空间使用情况? </think>### 解决 PostgreSQL 表中缺少 `partitions` 模块的问题 在 PostgreSQL 中,分区表功能是核心组件而非独立模块(如 Hive 的 `PARTITIONS` 表)。若遇到 "no partitions" 相关错误,通常由版本兼容性或配置问题引起。以下是系统化解决方案: --- ### 一、问题根源诊断 1. **版本不兼容** PostgreSQL 分区功能在 **v10+** 才完整支持(特别是声明式分区)。若版本 ≤ 9.6: ```sql SELECT version(); -- 验证版本 ``` **输出示例**: ``` PostgreSQL 9.5.25 on x86_64-pc-linux-gnu ... ``` 2. **表未正确定义为分区表** 分区表需显式指定 `PARTITION BY` 子句,否则系统不会识别为分区表。 3. **权限或元数据错误** 用户权限不足或系统目录损坏可能导致无法访问分区信息。 --- ### 二、分步解决方案 #### 步骤 1:升级 PostgreSQL(版本 ≤ 10 时必需) ```bash # Ubuntu 示例(升级到 PostgreSQL 14) sudo apt install postgresql-14 postgresql-contrib-14 sudo pg_dropcluster --stop 14 main sudo pg_upgradecluster 9.6 main ``` #### 步骤 2:正确创建分区表(v10+) ```sql -- 创建父表(范围分区示例) CREATE TABLE sensor_data ( id SERIAL, log_time TIMESTAMP NOT NULL, value FLOAT ) PARTITION BY RANGE (log_time); -- 创建子分区 CREATE TABLE sensor_data_2023 PARTITION OF sensor_data FOR VALUES FROM ('2023-01-01') TO ('2024-01-01'); ``` #### 步骤 3:查询分区信息(替代 `partitions` 模块) - **方法 1:使用系统视图** ```sql -- 获取所有分区表信息 SELECT * FROM pg_partitioned_table; -- 查看具体表的分区 SELECT relname AS partition_name FROM pg_inherits JOIN pg_class ON inhrelid = pg_class.oid WHERE inhparent = 'sensor_data'::regclass; ``` - **方法 2:内置函数(v12+)** ```sql SELECT * FROM pg_partition_tree('sensor_data'); ``` **输出示例**: | relid | parentrelid | isleaf | level | |-------------|--------------|--------|-------| | sensor_data | null | false | 0 | | sensor_data_2023 | sensor_data | true | 1 | #### 步骤 4:修复元数据错误 ```sql -- 重建表索引 REINDEX TABLE sensor_data; -- 更新统计信息 ANALYZE sensor_data; -- 检查权限 GRANT SELECT ON ALL TABLES IN SCHEMA public TO your_user; ``` --- ### 三、关键注意事项 1. **逻辑复制兼容性** PostgreSQL 10-12 的分区表在逻辑复制中需特殊处理(可能需触发器辅助)[^1]。 2. **分区剪枝优化** 确保查询条件包含分区键(如 `WHERE log_time BETWEEN '2023-06-01' AND '2023-06-30'`),否则无法触发剪枝。 3. **与传统继承分区区别** v10+ 的声明式分区无需手动管理继承关系,避免旧方案中 `CHECK` 约束的繁琐性。 --- ### 总结流程图 ```mermaid graph TD A[报错“no partitions”] --> B{检查版本} B -->|≤ 9.6| C[升级至PG 10+] B -->|≥ 10| D[验证表定义] D --> E[使用pg_partition_tree查询] E --> F[修复元数据/权限] F --> G[成功访问分区] ``` > **提示**:若问题持续,执行 `EXPLAIN ANALYZE SELECT ...` 可验证是否触发分区剪枝。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值