生成函数+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. 【LOJ】#2292. 「THUSC 2016」成绩单

    题解 神仙dp啊><(也有可能是我菜) 我们发现,想要拿一段区间的话,只和这个区间的最大值和最小值有关系,那么我们考虑,如果一个区间[l,r]我们拿走了一些数后,使它的最小值是a,最大值是 ...

  2. Android应用程序签名打包(AS)

    使用Android studio对Android应用签名步骤: 第一步: 第二步: 第三步: 第四步: 数字证书创建完成后,点击OK----->点击Next------>Finish. 注 ...

  3. forkcms 开启调试模式

    You can enable debug mode by adding "SetEnv FORK_DEBUG 1" in your virtualhosts file.

  4. linux 下nginx安装

    一.一键安装四个依赖 yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel 二.创建一个安装目录,并下载nginx安装 ...

  5. MXNet 中的几个数据集

    from mxnet import gluon def transform(data, label): return data.astype('float32') / 255., label.asty ...

  6. CSU - 2055 Wells‘s Lottery

    Description As is known to all, Wells is impoverished. When God heard that, God decide to help the p ...

  7. JAVAEE——宜立方商城07:Linux上搭建Solr服务、数据库导入索引库、搜索功能的实现

    1. 学习计划 1.Solr服务搭建 2.Solrj使用测试 3.把数据库中的数据导入索引库 4.搜索功能的实现 2. Solr服务搭建 2.1. Solr的环境 Solr是java开发. 需要安装j ...

  8. 顺序线性表之大整数求和C++实现

    顺序线性表之大整数求和 大整数求和伪代码 1.初始化进位标志 flag=0: 2.求大整数 A 和 B 的长度: int aLength = a.GetLength(); int bLength = ...

  9. BZOJ.1032.[JSOI2007]祖码(区间DP)

    题目链接 BZOJ 洛谷 AC代码: 区间DP,f[i][j]表示消掉i~j需要的最少珠子数. 先把相邻的相同颜色的珠子合并起来. 枚举方法一样,处理一下端点可以碰撞消除的情况就行. 当然合并会出现问 ...

  10. [Agc011F] Train Service Planning

    [Agc011F] Train Service Planning 题目大意: 有n+1个车站,n条轨道,第i条轨道联通i-1和i车站,通过它要花a[i]时间,这条轨道有b[i]=1或2条车道,也就是说 ...