[BZOJ 3771] Triple(FFT+生成函数)

题面

给出 n个物品,价值为别为\(w_i\)且各不相同,现在可以取1个、2个或3个,问每种价值和有几种情况?

分析

这种计数问题容易想到生成函数。

设生成函数\(A(x)=\sum_{i=1}^{n} x^{w_i}\),指数为价值,系数为选的方案数。A表示每种物品取1个的方案数。同理,我们可以写出每种物品取2个和3个的生成函数。

\(B(x)=\sum_{i=1}^{n} x^{2w_i}\)

\(C(x)=\sum_{i=1}^{n} x^{3w_i}\)

然后就开始大力容斥.

取3个不同物品的情况

直接取3个物品的方案数为\(A^3(x)\),但是我们还需要减去重复的,如\((a,a,b),(a,b,a)\)就算同一种情况。选2个物品\(a\)的方案为\(B(x)\),再选一个物品\(b\)的方案为\(A(x)\),任意排列有3种。因此要减\(3A(x)B(x)\)

然而每种物品取3个\((a,a,a)\)这样的方案会被减去3次,而实际上只需要减去1次,所以还要加回\(2C(x)\)

注意到\((a,b,c)\)的6种不同排列方案只算一次。总答案为

\[\frac{A^3(x)-3A(x)B(x)+2C(x)}{6}
\]

取2个不同物品的情况

直接取3个物品的方案为\(A^2(x)\)。重复的\((a,a)\)这种情况的方案为\(B(x)\),并且\((a,b)\)的2种排列只算1次。总答案为

\[\frac{A^2(x)-B(x))}{2}
\]

取1个不同物品的方案

很简单,就是\(A(x)\)

综上,总答案为

\[\frac{A^3(x)-3A(x)B(x)+2C(x)}{6}+\frac{A^2(x)-B(x))}{2}+A(x)
\]

先把A,B,C用FFT转成点值表达式然后相乘,再逆变换一下就得到答案.

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 400000
using namespace std;
typedef long long ll;
const double pi=acos(-1.0);
struct com{
double real;
double imag;
com(){ }
com(double _real,double _imag){
real=_real;
imag=_imag;
}
com(double x){
real=x;
imag=0;
}
void operator = (const com x){
this->real=x.real;
this->imag=x.imag;
}
void operator = (const double x){
this->real=x;
this->imag=0;
}
friend com operator + (com p,com q){
return com(p.real+q.real,p.imag+q.imag);
}
friend com operator + (com p,double q){
return com(p.real+q,p.imag);
}
friend com operator - (com p,com q){
return com(p.real-q.real,p.imag-q.imag);
}
friend com operator - (com p,double q){
return com(p.real-q,p.imag);
}
friend com operator * (com p,com q){
return com(p.real*q.real-p.imag*q.imag,p.real*q.imag+p.imag*q.real);
}
friend com operator * (com p,double q){
return com(p.real*q,p.imag*q);
}
friend com operator / (com p,double q){
return com(p.real/q,p.imag/q);
}
void print(){
printf("%lf + %lf i ",real,imag);
}
};
void fft(com *x,int n,int type){
static int rev[maxn+5];
int tn=1,k=0;
while(tn<n){
k++;
tn*=2;
}
for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
for(int i=0;i<n;i++) if(i<rev[i]) swap(x[i],x[rev[i]]);
for(int len=1;len<n;len*=2){
int sz=len*2;
com wn1=com(cos(2*pi/sz),type*sin(2*pi/sz));
for(int l=0;l<n;l+=sz){
int r=l+len-1;
com wnk=1;
for(int i=l;i<=r;i++){
com tmp=x[i+len];
x[i+len]=x[i]-wnk*tmp;
x[i]=x[i]+wnk*tmp;
wnk=wnk*wn1;
}
}
}
if(type==-1){
for(int i=0;i<n;i++) x[i].real/=n;
}
}
void mul(com *a,com *b,com *ans,int n){
// fft(a,n,1);
// fft(b,n,1);
//避免多次fft
for(int i=0;i<n;i++) ans[i]=a[i]*b[i];
fft(ans,n,-1);
} int n;
int val[maxn+5];
com a[maxn+5],b[maxn+5],c[maxn+5];
com ans[maxn+5];
int main(){
scanf("%d",&n);
int mv=0;
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
a[val[i]]=a[val[i]]+1;
b[val[i]*2]=b[val[i]*2]+1;
c[val[i]*3]=c[val[i]*3]+1;
mv=max(mv,val[i]);
}
int tn=1,k=0;
while(tn<mv*3){
k++;
tn*=2;
}
fft(a,tn,1);
fft(b,tn,1);
fft(c,tn,1);
for(int i=0;i<tn;i++){
ans[i]=(a[i]*a[i]*a[i]-3*a[i]*b[i]+2*c[i])/6+(a[i]*a[i]-b[i])/2+a[i];
}
fft(ans,tn,-1);
for(int i=0;i<=mv*3;i++){
if(ll(ans[i].real+0.5)){
printf("%d %lld\n",i,ll(ans[i].real+0.5));
}
}
}

[BZOJ 3771] Triple(FFT+容斥原理+生成函数)的更多相关文章

  1. BZOJ 3771 Triple FFT+容斥原理

    解析: 这东西其实就是指数型母函数? 所以刚开始读入的值我们都把它前面的系数置为1. 然后其实就是个多项式乘法了. 最大范围显然是读入的值中的最大值乘三,对于本题的话是12W? 用FFT优化的话,达到 ...

  2. bzoj 3771 Triple FFT 生成函数+容斥

    Triple Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 847  Solved: 482[Submit][Status][Discuss] Desc ...

  3. BZOJ 3771: Triple [快速傅里叶变换 生成函数 容斥原理]

    题意:n个物品,可以用1/2/3个不同的物品组成不同的价值,求每种价值有多少种方案(顺序不同算一种) [生成函数]: 构造这么一个多项式函数g(x),使得n次项系数为a[n]. 普通型生成函数用于解决 ...

  4. bzoj 3771 Triple——FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3771 把方案作为系数.值作为指数,两项相乘就是系数相乘.指数相加,符合意义. 考虑去重.先自 ...

  5. bzoj 3771 Triple —— FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3771 令多项式的系数是方案数,次数是值: 设 a(x) 为一个物品的多项式,即 a[w[i] ...

  6. BZOJ 3771 Triple ——FFT

    直接暴力卷积+统计就可以了. 去重比较复杂. 其实也不复杂,抄吧! 反正AC了. #include <map> #include <cmath> #include <qu ...

  7. BZOJ 3771: Triple(FFT+容斥)

    题面 Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: "这把斧头,是不是你的?" 樵夫一看:&qu ...

  8. 【BZOJ 3771】 3771: Triple (FFT+容斥)

    3771: Triple Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 547  Solved: 307 Description 我们讲一个悲伤的故事. ...

  9. BZOJ 3771: Triple

    Description 问所有三/二/一元组可能形成的组合. Sol FFT. 利用生成函数直接FFT一下,然后就是计算,计算的时候简单的容斥一下. 任意三个-3*两个相同的+2*全部相同的+任意两个 ...

随机推荐

  1. 小小程序员的生产力工具——2017款MacBook pro 13.3(附使用技巧和常用链接)

    新买的2017款 MacBook pro 13.3 九号到了,第一次用苹果笔记本,用了两天基本熟悉了,各种软件也安装的差不多,把一些小技巧分享给大家.先放几张图   使用小常识,希望可以帮到您一:尽量 ...

  2. GO语言学习笔记6-Sort的使用

    GoLang标准库的sort包提供了排序切片和用户自定义数据集以及相关功能的函数. Sort操作的对象通常是一个slice,需要满足三个基本的接口,并且能够使用整数来索引. 1.sort实现原理 So ...

  3. 电脑右键新建没有xmind文件选项解决方法

    xmind还是方便的. 打开注册表,展开HKEY_CLASSES_ROOT,展开.xmind(如果没有请新建).在里面新建ShellNew项,并展开,在里面新建NullFile这个字符串值. 如果还是 ...

  4. [转] 数值优化(Numerical Optimization)学习系列-目录

    from:https://blog.csdn.net/fangqingan_java/article/details/48951191 概述数值优化对于最优化问题提供了一种迭代算法思路,通过迭代逐渐接 ...

  5. @JsonView注解指定返回的model类中显示的字段

    1.User类 package com.imooc.model; import com.fasterxml.jackson.annotation.JsonView; /** * @author oy ...

  6. BZOJ 4597: [Shoi2016]随机序列 线段树 + 思维

    Description 你的面前有N个数排成一行.分别为A1, A2, … , An.你打算在每相邻的两个 Ai和 Ai+1 间都插入一个加号或者 减号或者乘号.那么一共有 3^(n-1) 种可能的表 ...

  7. [CF1093G]Multidimensional Queries 题解

    前言 DennyQi太巨了! 定义一个点\(a\),\(a_x\)表示\(a\)在第\(x\)维空间上的坐标值 题解 这题的思路珂以说非常巧妙(原谅我又用了这个"珂"), 我们知道 ...

  8. Cisco基础(三):HSRP配置、三层交换配置HSRP、STP的配置、三层交换配置STP

    一.HSRP配置 目标: 在企业网络到外部的连接方案中,要求不高的条件下可以是单出口.一旦该出口线路出现问题,整个企业网络就不能连接到外网了.为了使得企业网络到外网连接的高可用性,可以设置两个以上的出 ...

  9. Python字典实现

    这篇文章描述了在Python中字典是如何实现的. 字典通过键(key)来索引,它可以被看做是关联数组.我们在一个字典中添加3个键/值对: >>> d = {'a': 1, 'b': ...

  10. SRCNN 卷积神经网络

    2019-05-19 从GitHub下载了代码(这里) 代码量虽然不多,但是第一次学,花了时间还是挺多的.根据代码有跑出结果(基本没有改),但是对于数据集的处理还是看的很懵逼,主要是作者的实现都是用类 ...