Typesetting math: 100%

【BZOJ 3771】Triple

Problem#

Description#

给出 nn 个物品,第 ii 个物品体积为 aiai

对于每个体积 VV ,求选出 33 个物品,体积之和为 VV 的方案总数。

选择顺序不同算同一种方案。

Range#

nn 保证不会读入到 TLETLEai4×104ai4×104

Algorithm#

多项式,生成函数。

Mentality#

设生成函数 A(x)A(x) 为只选择一个物品的生成函数。其中 [xm]A(x)[xm]A(x) 的系数代表了体积 mm 有多少种选法。

同理设 B(x)B(x) 为选择两个相同物品的生成函数,设 C(x)C(x) 为选择三个相同物品的生成函数。

则对于最后的答案而言:

若选择的 33 个物品互不相同,则方案数为:

A3(x)3B(x)A(x)+2C(x)6A3(x)3B(x)A(x)+2C(x)6

因为根据容斥,A3(x)A3(x) 等于所有选择三个物品的方案数,B(x)A(x)B(x)A(x) 则是所有形如 (a,a,b)(a,a,b) 的方案数,由于这种方案在 A3(x)A3(x) 会出现三次,所以要乘 33 ,然后对于所有 (a,a,a)(a,a,a) ,也即生成函数 C(x)C(x)B(x)A(x)B(x)A(x) 中出现了 33 次,但实际上在 A3(x)A3(x) 只会被计算一次,所以还要加回 22 个来。

若选择 22 个物品,那么方案为:

A2(x)B(x)2A2(x)B(x)2

这个很好理解。

选择一个物品的方案自然就是 A(x)A(x) 了。

FFTFFT 即可。

Code#

Copy
#include <cmath> #include <complex> #include <cstdio> #include <iostream> using namespace std; #define LL long long #define cp complex<double> #define inline __inline__ __attribute__((always_inline)) inline LL read() { LL x = 0, w = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); } while (isdigit(ch)) { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); } return x * w; } const int Max_n = 4e5 + 5, Ml = 1.2e5; const double pi = acos(-1); cp ans[Max_n], A[Max_n], B[Max_n], C[Max_n]; namespace Input { void main() { int n = read(); for (int i = 1, x; i <= n; i++) x = read(), A[x] += 1, B[x * 2] += 1, C[x * 3] += 1; } } // namespace Input namespace Solve { int bit, len, rev[Max_n]; void init() { int bit = log2(Ml + 1) + 1; len = 1 << bit; for (int i = 0; i < len; i++) rev[i] = rev[i >> 1] >> 1 | ((i & 1) << (bit - 1)); } void dft(cp *f, int t) { for (int i = 0; i < len; i++) if (i < rev[i]) swap(f[i], f[rev[i]]); for (int l = 1; l < len; l <<= 1) { cp Wn(cos(t * pi / (double)l), sin(t * pi / (double)l)); for (int i = 0; i < len; i += (l << 1)) { cp Wnk(1, 0); for (int k = i; k < i + l; k++, Wnk *= Wn) { cp x = f[k], y = f[k + l] * Wnk; f[k] = x + y, f[k + l] = x - y; } } } } void main() { init(); dft(A, 1), dft(B, 1), dft(C, 1); for (int i = 0; i < len; i++) { ans[i] = (A[i] * A[i] * A[i] - A[i] * B[i] * 3.0 + 2.0 * C[i]) / 6.0; ans[i] += (A[i] * A[i] - B[i]) / 2.0 + A[i]; } dft(ans, -1); for (int i = 0; i <= Ml; i++) ans[i] /= (double)len; for (int i = 0; i <= Ml; i++) { LL Ans = (LL)(ans[i].real() + 0.5); if (Ans) printf("%d %lld\n", i, Ans); } } } // namespace Solve int main() { Input::main(); Solve::main(); }
posted @   洛水·锦依卫  阅读(162)  评论(0编辑  收藏  举报
编辑推荐:
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
阅读排行:
· 趁着过年的时候手搓了一个低代码框架
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· 乌龟冬眠箱湿度监控系统和AI辅助建议功能的实现
点击右上角即可分享
微信分享提示

目录

目录

×