繁凡出品的全新系列:解题报告系列 —— 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 111 为基准。


这样大家在学习算法的时候就可以执行这样的流程:

%
阅读我的【学习笔记】 / 【算法全家桶】学习算法 ⇒\Rightarrow⇒ 阅读我的相应算法的【解题报告】获得高质量题单 ⇒\Rightarrow⇒ 根据我的一句话题解的提示尝试自己解决问题 ⇒\Rightarrow⇒ 点开我的详细题解链接学习巩固(好耶)
%

题单链接:【解题报告】多项式问题(多项式乘法及其各种运算)(ICPC / CCPC / NOIP / CF / AT / NC / P)超高质量题解

BZOJ 没了呜呜呜

C、(BZOJ 3771)Triple(生成函数 + FFT)(3)

Link

https://darkbzoj.tk/problem/3771

Problem

我们讲一个悲伤的故事。
从前有一个贫穷的樵夫在河边砍柴。
这时候河里出现了一个水神,夺过了他的斧头,说:
“这把斧头,是不是你的?”
樵夫一看:“是啊是啊!”
水神把斧头扔在一边,又拿起一个东西问:
“这把斧头,是不是你的?”
樵夫看不清楚,但又怕真的是自己的斧头,只好又答:“是啊是啊!”
水神又把手上的东西扔在一边,拿起第三个东西问:
“这把斧头,是不是你的?”
樵夫还是看不清楚,但是他觉得再这样下去他就没法砍柴了。
于是他又一次答:“是啊是啊!真的是!”
水神看着他,哈哈大笑道:
“你看看你现在的样子,真是丑陋!”
之后就消失了。
樵夫觉得很坑爹,他今天不仅没有砍到柴,还丢了一把斧头给那个水神。
于是他准备回家换一把斧头。
回家之后他才发现真正坑爹的事情才刚开始。
水神拿着的的确是他的斧头。
但是不一定是他拿出去的那把,还有可能是水神不知道怎么偷偷从他家里拿走的。
换句话说,水神可能拿走了他的一把,两把或者三把斧头。
樵夫觉得今天真是倒霉透了,但不管怎么样日子还得过。
他想统计他的损失。
樵夫的每一把斧头都有一个价值,不同斧头的价值不同。总损失就是丢掉的斧头价值和。
他想对于每个可能的总损失,计算有几种可能的方案。
注意:如果水神拿走了两把斧头a和b,(a,b)和(b,a)视为一种方案。拿走三把斧头时,(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)视为一种方案。

Input

第一行是整数N,表示有N把斧头。
接下来n行升序输入N个数字Ai,表示每把斧头的价值。

Output

若干行,按升序对于所有可能的总损失输出一行x y,x为损失值,y为方案数。

Solution

题意可以简化为:

给定 nnn 个互不相同的数,问你从这 nnn 个数中选出 1,2,31,2,31,2,3个(不能重复选),所选的三个数的和的方案数是多少,输出所有可能的和 xxx 以及 xxx 的方案数 yyy 。

注:若选取了两个数 aaa 和 bbb ,(a,b)(a,b)(a,b) 和 (b,a)(b,a)(b,a) 视为一种方案。若选取了三个数 aaa 、 bbb 和 ccc,(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)视为一种方案。

这是一个比较基础的生成函数的应用。

nnn 个数只能选一次,有这个限制条件不好直接计算,正难则反,我们可以先忽略这个限制条件,也就是先考虑每个数可以选择任意次的方案数,然后利用容斥原理(奇加偶减)减去重复选的方案数即可。

我们这里使用生成函数,因为这里的价值是每个数的权值而不是个数什么的,所以我们设若选择了一个权值为 www 的物品,则 xwx^wxw 的系数 a[w] ++

这样我们就可以设 A(x)A(x)A(x) 表示每个物品选择一次的生成函数, B(x)B(x)B(x) 表示每个物品选择两次的生成函数, C(x)C(x)C(x) 表示每个物品选择三次的生成函数。

  • 先考虑选择三个物品的情况

考虑去掉重复。

选择了三个物品,首先考虑有同一个物品选择了两次的冗余情况,即三个物品中有两个是重复选择的,也就是 C32C_{3}^{2}C32​,两个重复选择的方案数为 B(x)B(x)B(x),乘上剩下一个物品 A(x)A(x)A(x),此时答案减去 C32×B(x)×A(x)=3B(x)A(x)C_3^2\times B(x)\times A(x)=3B(x)A(x)C32​×B(x)×A(x)=3B(x)A(x)。

然后考虑有同一个物品选择了三次的冗余情况。

很明显同一个物品选择了三次的方案数为 C(x)C(x)C(x),但是我们在同一个物品选择了两次的时候已经减去过了,因为两个相同,加上另一个,另一个也有可能与这两个相同。并且因为上面减去的时候减掉了三倍,也就是多减了两倍,所以再加上二倍,即答案再加上2×C(x)2\times C(x)2×C(x)。(奇加偶减)

最后因为题目中说了选择三个物品的时候有 666 种是重复的,所以需要除以 666。

即选择三个物品的方案数为:
ans=A(x)3−3B(x)A(x)+2C(x)6ans=\frac{A(x)^3-3B(x)A(x)+2C(x)}{6} ans=6A(x)3−3B(x)A(x)+2C(x)​

  • 再考虑选择两个物品的情况

显然不考虑重复选择两个物品的方案数为 A(x)2A(x)^2A(x)2,去掉冗余,即减去 B(x)B(x)B(x)。因为 B(x)B(x)B(x) 的含义就是一个物品被选择了两次。

并且题目种告诉我们了选择两个数有两种是重复的,所以除以 222。

即选择两个物品的方案数为:

ans=A(x)2−B(x)2ans= \frac{A(x)^2-B(x)}{2} ans=2A(x)2−B(x)​

  • 最后考虑选择一个物品的情况

显然此时方案数为 A(x)A(x)A(x)

故总方案数为:

ans=A(x)3−3B(x)A(x)+2C(x)6+A(x)2−B(x)2+A(x)ans=\frac{A(x)^3-3B(x)A(x)+2C(x)}{6}+\frac{A(x)^2-B(x)}{2}+A(x) ans=6A(x)3−3B(x)A(x)+2C(x)​+2A(x)2−B(x)​+A(x)

直接FFT求卷积即可。

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <queue>
using namespace std;
typedef long long ll;
typedef int itn;
typedef pair<int, int>PII;
const int N = 2e5 + 7, mod = 1e9 + 7;
const double PI = acos(-1.0);int n, m, limit, L, RR[N], maxx;struct Complex
{double x, y;Complex(double x = 0, double y = 0) : x(x), y(y) { }
}a[N], A[N], B[N], C[N], D[N], ans[N];Complex operator + (Complex a, Complex b) {return Complex(a.x + b.x, a.y + b.y);}
Complex operator - (Complex a, Complex b) {return Complex(a.x - b.x, a.y - b.y);}
Complex operator * (Complex a, Complex b) {return Complex(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);}void FFT(Complex *A, int type)
{for(int i = 0; i < limit; ++ i)if(i < RR[i])swap(A[i], A[RR[i]]);for(int mid = 1; mid < limit; mid <<= 1) {Complex wn(cos(PI / mid), (double)type * sin(PI / mid));for(int len = mid << 1, pos = 0; pos < limit; pos += len) {Complex w(1, 0);for(int k = 0; k < mid; ++ k, w = w * wn) {Complex x = A[pos + k];Complex y = w * A[pos + k + mid];A[pos + k] = x + y;A[pos + mid + k] = x - y;}}}if(type == -1) {for(int i = 0; i < limit; ++ i) {A[i].x /= limit;}}
}void solve()
{Complex w3(3.0, 0);Complex w2(2.0, 0), w1in6(1.0 / 6.0, 0), w1in2(1.0 / 2.0, 0);scanf("%d", &n);for(int i = 1; i <= n; ++ i) {int x;scanf("%d", &x);A[x].x ++ , B[x * 2].x ++ , C[x * 3].x ++ ;maxx = max(maxx, x * 3);}limit = 1, L = 0;while(limit <= maxx) limit <<= 1, L ++ ;for(int i = 0; i < limit; ++ i) {RR[i] = (RR[i >> 1] >> 1) | ((i & 1) << (L - 1));}FFT(A, 1), FFT(B, 1), FFT(C, 1);for(int i = 0; i <= limit; ++ i) {ans[i] = ans[i] + ((A[i] * A[i] * A[i] - w3 * B[i] * A[i] + w2 * C[i]) * w1in6);ans[i] = ans[i] + (A[i] * A[i] - B[i]) * w1in2;ans[i] = ans[i] + A[i];}FFT(ans, -1);for(int i = 0; i < limit; ++ i) {int res = (int)(ans[i].x + 0.5);if(res)printf("%d %d\n", i, res);}
}int main()
{solve();
}

解题报告(二)C、(darkBZOJ 3771)Triple(生成函数 + FFT + 容斥原理)(3)相关推荐

  1. #3771. Triple 生成函数 + FFT + 容斥

    传送门 文章目录 题意: 思路: 题意: 思路: 注意到这个题是求若干个数的组合数,(a,b),(b,a)(a,b),(b,a)(a,b),(b,a)视为一种方案,所以我们考虑生成一个普通型生成函数. ...

  2. 【洛谷新手村解题报告二】C++语言,一题多解,思路和WA反思

    [洛谷新手村解题报告二] 循环!循环!循环! 数组 继续上次的一!开始循环第二题 循环!循环!循环! 第二题 级数求和 [1/2] 已知:Sn= 1+1/2+1/3+-+1/n 显然对于任意一个整数 ...

  3. [精品]CSAPP Bomb Lab 解题报告(二)

    接上篇[精品]CSAPP Bomb Lab 解题报告(一) gdb常用指令 设置Intel代码格式:set disassembly-flavor intel 查看反汇编代码:disas phase_1 ...

  4. BZOJ3771 Triple(FFT+容斥原理)

    思路比较直观.设A(x)=Σxai.先把只选一种的统计进去.然后考虑选两种,这个直接A(x)自己卷起来就好了,要去掉选同一种的情况然后除以2.现在得到了选两种的每种权值的方案数,再把这个卷上A(x). ...

  5. [精品]CSAPP Bomb Lab 解题报告(三)

    接上篇[精品]CSAPP Bomb Lab 解题报告(二) gdb常用指令 设置Intel代码格式:set disassembly-flavor intel 查看反汇编代码:disas phase_1 ...

  6. 解题报告(二)E、(BZOJ3513) [MUTC2013] idiots(生成函数 + FFT + 组合计数)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  7. 解题报告(二)C、(darkBZOJ 2194) 快速傅立叶之二(FFT、卷积的概念、常用变换)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  8. 解题报告(四)生成函数(ACM/ OI)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  9. 解题报告(二)多项式问题(多项式乘法及其各种运算)(ACM/ OI)超高质量题解

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

最新文章

  1. Chart.js-雷达图分析(参数分析+例图)
  2. zabbix_get 无法获取值(解决思路)
  3. 脑电分析系列[MNE-Python-15]| Epochs数据可视化
  4. 使用MediaCodeC将图片集编码为视频
  5. mysql临时表好处和坏处_mysql临时表产生的执行效率问题改进(转)
  6. spring in action小结4.1
  7. C++ 如何判断所调用的重载函数
  8. SAP UI5 货币金额显示的格式化逻辑
  9. 糍粑大叔的独游之旅-战斗!之弹道实现(上)
  10. Linux虚拟化KVM-Qemu分析(六)之中断虚拟化
  11. intellij idea rearrange code
  12. android游戏boss坐标,混沌与秩序2已知boss刷新点分布图详解(已更新到20号boss)...
  13. 软件开发过程中的一些感悟
  14. android_x86安装arm转译
  15. iOS小技能:金额格式处理 (货币符号本地化)
  16. 苹果官方mfi认证名单_苹果入驻抖音,完成官方认证
  17. 1 -- > PCI / PCIe 配置空间详解
  18. 计算机基础文化课认识,【计算机基础论文】计算机基础的教学改革解析(共4653字)...
  19. 微信小程序顶部渐变色实现
  20. 【 bzoj 4355 】 Play with sequence - 线段树乱搞

热门文章

  1. 深度学习在超市商品识别中的解决方案分享
  2. 初学者必备的数组相关知识点
  3. 详解 | 自动泊车中鱼眼相机实现车位线感知
  4. 实战:基于深度学习的道路损坏检测
  5. python逐行读取文本
  6. Java list三种遍历方法性能比较
  7. 用JPUSH极光推送实现服务端向安装了APP应用的手机推送消息(C#服务端接口)
  8. ORACLE HANDBOOK系列之十四:变化通知(Change Notification)
  9. python猿辅导_如何用数据分析方法剖析“猿辅导”K12课程
  10. Linux重定向和管道符使用避坑指南