生成函数+FFT

  Orz PoPoQQQ

  这个题要算组合的方案,而且范围特别大……所以我们可以利用生成函数来算

  生成函数是一个形式幂级数,普通生成函数可以拿来算多重集组合……好吧我承认以上是在瞎扯→_→

  这个东西我也不记得是多会儿看的了……找本《组合数学》自己看看好了……或者问学数学竞赛的同学&数竞教练

先引用下PoPoQQQ的题解:

首先搞出这n个物品的母函数a
将a的每项的平方求和得到多项式b
将a的每项的立方求和得到多项式c
那么如果不考虑顺序和重复 那么方案数就是a+b+c
现在考虑顺序和重复后
三个物品的方案数为(a^3-3*a*b+2*c)/6
两个物品的方案数为(a^2-b)/2
一个物品的方案数为a
故最终答案为(a^3-3*a*b+2*c)/6+(a^2-b)/2+a
用FFT搞一下就好了- -

  

  我们可以这样定义一个多项式(生成函数)A=a0+a1*x+a2*(x^2)+a3*(x^3)+……(为什么要说它是形式幂级数呢?我觉得是因为我们不考虑x的值具体是多少,只考虑x^i 的系数!运算的时候就像大整数乘法那样算)

  如果我们有一把斧头的价值是w,我们就令x^w这一项的系数为1,然后我们可以这样算:

    1.A的每一项 x^i 的系数表示取1柄斧头价值为 i 的方案数

    2.A*A的每一项 x^i 的系数表示取两柄斧头总价值为 i 的方案数:

    比如我们有价值为3、4、5和6的斧头,那么在A这个多项式中,x^3、x^4、x^5和x^6的系数就为1,其他都为0,所以在A*A里面,x^9的系数为2,因为(x^3)*(x^6)=x^9,(x^4)*(x^5)=x^9;所以x^9这一项的系数为2,也就是说我们取两柄斧头有两种方案使得总价值为9.

    但是这样算出来的并不全对,因为这样会出现 (x^3)*(x^3)=(x^6)的情况,也就是一把斧头取了两遍的方案,这种是需要减去的,所以我们再定义一个多项式B,满足 x^(w[i]*2) 的系数为1,那么A*A-B的答案就是总的方案数。

    但是!!这样的方案是算了2遍的,因为(x^3)*(x^6)=(x^9)且(x^6)*(x^3)=(x^9)(注意我们是让A自己乘自己)所以答案应该是 0.5 * (A*A-B)

    3.A*A*A表示取三把斧头,同样,我们要去掉不合法的方案,并且乘以(1/6),因为三个斧头我们一共算了6次(全排列)

【重要】:本题使用FFT的时候,是对w[i]的范围进行多项式乘法的,而不是斧头的数量N!!!这点要注意,所以所有的FFT的范围都需是131072!!

总结:本题是利用生成函数来进行组合方案数的求解,这种方法的优势在于是用多项式的系数来表示的,所以可以用FFT加速。然而生成函数本身是用来算多重集组合数的,所以本题在使用的时候还需要进行对不合法方案的排除,这里用到了容斥原理(勉为其难地如此说吧)。

 /**************************************************************
Problem: 3771
User: Tunix
Language: C++
Result: Accepted
Time:1500 ms
Memory:9464 kb
****************************************************************/ //BZOJ 3771
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
using namespace std;
int getint(){
int v=,sign=; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') sign=-; ch=getchar();}
while(isdigit(ch)) {v=v*+ch-''; ch=getchar();}
return v*sign;
}
/*******************template********************/
const int N=;
const double pi=acos(-),eps=1e-;
struct comp{
double r,i;
comp(double _=0.0,double __=0.0):r(_),i(__){}
comp operator + (const comp&b)const{return comp(r+b.r,i+b.i);}
comp operator - (const comp&b)const{return comp(r-b.r,i-b.i);}
comp operator * (const comp&b)const{return comp(r*b.r-i*b.i,r*b.i+i*b.r);}
friend comp operator * (double x,comp b){return comp(b.r*x,b.i*x);}
}a[N],b[N],c[N],ans[N];
void FFT(comp *a,int n,int type){
for(int i=,j=;i<n-;++i){
for(int s=n;j^=s>>=,~j&s;);
if (i<j) swap(a[i],a[j]);
}
for(int m=;m<n;m<<=){
double u=pi/m*type; comp wm(cos(u),sin(u));
for(int i=;i<n;i+=(m<<)){
comp w(,);
rep(j,m){
comp &A=a[i+j+m],&B=a[i+j],t=w*A;
A=B-t; B=B+t; w=w*wm;
}
}
}
if (type==-) rep(i,n) a[i].r/=n;
} int main(){
// freopen("input.txt","r",stdin);
int n=getint(),len=N,x;
// for(len=1;len<=(n<<1);len<<=1);
rep(i,n){
x=getint();
a[x ]=comp(,);
b[x*]=comp(,);
c[x*]=comp(,);
}
FFT(a,len,); FFT(b,len,); FFT(c,len,);
rep(i,len){
ans[i]=ans[i]+(1.0/6.0)*(a[i]*a[i]*a[i]-3.0*b[i]*a[i]+*c[i]);
ans[i]=ans[i]+(0.5)*(a[i]*a[i]-b[i]);
ans[i]=ans[i]+a[i];
}
FFT(ans,len,-);
rep(i,len){
x=int(ans[i].r+eps);
if (x) printf("%d %d\n",i,x);
}
return ;
}

【BZOJ】【3771】Triple的更多相关文章

  1. 【Bzoj 1835 基站选址】

    基站选址的区间里隐藏着DP优化的机密…… 分析:       不论是做过乘积最大还是石子合并,或者是其他的入门级别的区间DP题目的人呐,大米并认为读题后就能够轻松得出一个简洁明了的Dp转移方程.    ...

  2. 【BZOJ 2744 朋友圈】

    Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1570  Solved: 532[Submit][Status][Discuss] Descripti ...

  3. 【BZOJ 5038 不打兔子】

    Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 22  Solved: 8[Submit][Status][Discuss] Description 勤 ...

  4. 【BZOJ 1088 扫雷Mine】模拟

    http://www.lydsy.com/JudgeOnline/problem.php?id=1088 2*N的扫雷棋盘,第二列的值a[i]记录第 i 个格子和它8连通的格子里面雷的数目. 第一列的 ...

  5. 【BZOJ做题记录】07.07~?

    在NOI一周前重开一个坑 最后更新时间:7.08 07:38 7.06 下午做的几道CQOI题: BZOJ1257: [CQOI2007]余数之和sum:把k mod i写成k-k/i*i然后分段求后 ...

  6. 【bzoj5050】【bzoj九月月赛H】建造摩天楼

    讲个笑话,这个题很休闲的. 大概是这样的,昨天看到这个题,第一眼星际把题目看反了然后感觉这是个傻逼题. 后来发现不对,这个修改一次的影响是很多的,可能导致一个数突然可以被改,也可能导致一个数不能被改. ...

  7. 【BZOJ 4151 The Cave】

    Time Limit: 5 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 293  Solved: 144[Submit][Status][Di ...

  8. 【BZOJ 2458 最小三角形】

    Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1551  Solved: 549[Submit][Status][Discuss] Descripti ...

  9. 【BZOJ 5000 OI树】

    Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 107  Solved: 64[Submit][Status][Discuss] Description ...

  10. 【BZOJ 5047 空间传送装置】

    Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 282  Solved: 121[Submit][Status][Discuss] Descriptio ...

随机推荐

  1. 用 Java 实现一个插入排序算法

    有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法:插入排序法.插入排序的基本操作就是将一个数据插入到已经排好序的有序 ...

  2. linux 下rocketmq安装

    一.解压mq(/data下)tar -zxvf Rocketmq-3.5.8.tar.gz 二.修改配置文件vi /etc/profileexport rocketmq=/data/alibaba-r ...

  3. <泛> STL - vector 模拟实现

    今天为大家带来一个模拟STL-vector的模板实现代码. 首先看一下测试结果,之后再为大家呈现设计 测试效果 测试代码 #include<iostream> #include<ve ...

  4. To 初识Java的小菜菜们 嘻嘻~

    一.Java Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言.Java 技术具有卓越的通用性.高效性.平台移植性和安全性,广泛应用于PC.数据中心.游戏控制台.科学超级计算机.移动电话和 ...

  5. 使用DNSPod域名解析

    1 在GoDaddy域名注册商 注册域名 https://sg.godaddy.com/zh/ 2 登陆DNSPod https://www.dnspod.cn 3 选择域名解析 添加域名 4 添加记 ...

  6. 深入理解ajax系列第九篇

    前面的话 jQuery提供了一些日常开发中需要的快捷操作,例如load.ajax.get和post等,使用jQuery开发ajax将变得极其简单.这样开发人员就可以将程序开发集中在业务和用户体验上,而 ...

  7. opencv 加载 修改 保存 图像

    #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; /* 1 加载图像 cv::imre ...

  8. 机器学习之路: python nltk 文本特征提取

    git: https://github.com/linyi0604/MachineLearning 分别使用词袋法和nltk自然预言处理包提供的文本特征提取 from sklearn.feature_ ...

  9. 希尔排序之C++实现(高级版)

    希尔排序之C++实现(高级版) 一.源代码:ShellSortHigh.cpp /*希尔排序基本思想: 先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组. 所有距离为d1的倍数的记录放在同 ...

  10. 选择排序之C++实现

    选择排序之C++实现 一.源代码:SelectSort.cpp /* 选择排序(从小到大)的基本思想是,首先,选出最小的数,放在第一个位置: 然后,选出第二小的数,放在第二个位置: 以此类推,直到所有 ...