SPOJ TSUM Triple Sums(FFT + 容斥)
题目
Source
http://www.spoj.com/problems/TSUM/
Description
You're given a sequence s of N distinct integers.
Consider all the possible sums of three integers from the sequence at three different indicies.
For each obtainable sum output the number of different triples of indicies that generate it.
Constraints:
N <= 40000, |si| <= 20000
Input
The first line of input contains a single integer N.
Each of the next N lines contain an element of s.
Output
Print the solution for each possible sum in the following format:
sum_value : number_of_triples
Smaller sum values should be printed first.
Sample Input
5
-1
2
3
0
5
Sample Output
1 : 1
2 : 1
4 : 2
5 : 1
6 : 1
7 : 2
8 : 1
10 : 1
分析
题目大概说给n个数,从中选出三个数求和,问能到的各个和分别有几种取法能够得到?
这题很容易。。因为刚做过HDU4609。。
就是根据初始的序列构造出三个一样的多项式,指数表示数字,系数表示该数字出现次数。
然后三个多项式的乘积相当于表示有顺序有放回地取数字的结果。这个用FFT求。
不过这不是组合,可以用容斥原理去掉那些取法重复的。
即减去3种两个取同一边的情况,这个也用FFT求;然后加上三个都取同一边的情况,for一遍即可求;最后除以3的阶乘。
注意到时间好像比较紧,所以我做了些处理,比如三个多项式相乘直接三个点值相乘、避免重复的DFT过程。。
。。然后没想到居然暂时列第二,与第一同时间:

代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAXN 131072
const double PI=acos(-1.0); struct Complex{
double real,imag;
Complex(double _real=0,double _imag=0):real(_real),imag(_imag){}
Complex operator+(const Complex &cp) const{
return Complex(real+cp.real,imag+cp.imag);
}
Complex operator-(const Complex &cp) const{
return Complex(real-cp.real,imag-cp.imag);
}
Complex operator*(const Complex &cp) const{
return Complex(real*cp.real-imag*cp.imag,real*cp.imag+cp.real*imag);
}
void setValue(double _real=0,double _imag=0){
real=_real; imag=_imag;
}
}; int len;
Complex wn[MAXN+1],wn_anti[MAXN+1]; void FFT(Complex y[],int op){
for(int i=1,j=len>>1,k; i<len-1; ++i){
if(i<j) swap(y[i],y[j]);
k=len>>1;
while(j>=k){
j-=k;
k>>=1;
}
if(j<k) j+=k;
}
for(int h=2; h<=len; h<<=1){
Complex Wn=(op==1?wn[h]:wn_anti[h]);
for(int i=0; i<len; i+=h){
Complex W(1,0);
for(int j=i; j<i+(h>>1); ++j){
Complex u=y[j],t=W*y[j+(h>>1)];
y[j]=u+t;
y[j+(h>>1)]=u-t;
W=W*Wn;
}
}
}
if(op==-1){
for(int i=0; i<len; ++i) y[i].real/=len;
}
} Complex A[MAXN],B[MAXN];
double ans[MAXN];
int s[40100],cnt[80100]; int main(){
for(int i=0; i<=MAXN; ++i){
wn[i].setValue(cos(2.0*PI/i),sin(2.0*PI/i));
wn_anti[i].setValue(wn[i].real,-wn[i].imag);
} int n;
scanf("%d",&n);
for(int i=0; i<n; ++i){
scanf("%d",&s[i]);
s[i]+=20000;
++cnt[s[i]];
} len=MAXN; for(int i=0; i<=40000; ++i){
B[i].setValue(cnt[i]);
}
FFT(B,1);
for(int i=0; i<MAXN; ++i){
A[i]=B[i]*B[i]*B[i];
}
FFT(A,-1);
for(int i=0; i<MAXN; ++i){
ans[i]=A[i].real;
} memset(cnt,0,sizeof(cnt));
for(int i=0; i<n; ++i){
++cnt[s[i]+s[i]];
}
for(int i=0; i<=80000; ++i){
A[i].setValue(cnt[i]);
}
for(int i=80001; i<MAXN; ++i){
A[i].setValue(0);
}
FFT(A,1);
for(int i=0; i<MAXN; ++i){
A[i]=A[i]*B[i];
}
FFT(A,-1);
for(int i=0; i<MAXN; ++i){
ans[i]-=3*A[i].real;
} for(int i=0; i<n; ++i){
++ans[s[i]+s[i]+s[i]];
} for(int i=0; i<MAXN; ++i){
long long tmp=(long long)(ans[i]/6.0+0.5);
if(tmp){
printf("%d : %lld\n",i-60000,tmp);
}
}
return 0;
}
SPOJ TSUM Triple Sums(FFT + 容斥)的更多相关文章
- spoj TSUM - Triple Sums fft+容斥
题目链接 首先忽略 i < j < k这个条件.那么我们构造多项式$$A(x) = \sum_{1现在我们考虑容斥:1. $ (\sum_{}x)^3 = \sum_{}x^3 + 3\s ...
- BZOJ.3771.Triple(母函数 FFT 容斥)
题目链接 \(Description\) 有\(n\)个物品(斧头),每个物品价值不同且只有一件,问取出一件.两件.三件物品,所有可能得到的价值和及其方案数.\((a,b),(b,a)\)算作一种方案 ...
- 【BZOJ 3771】 3771: Triple (FFT+容斥)
3771: Triple Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 547 Solved: 307 Description 我们讲一个悲伤的故事. ...
- BZOJ 3771: Triple(FFT+容斥)
题面 Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: "这把斧头,是不是你的?" 樵夫一看:&qu ...
- HDU 4609 3-idiots FFT+容斥
一点吐槽:我看网上很多分析,都是在分析这个题的时候,讲了半天的FFT,其实我感觉更多的把FFT当工具用就好了 分析:这个题如果数据小,统计两个相加为 x 的个数这一步骤(这个步骤其实就是求卷积啊),完 ...
- Spoj 8372 Triple Sums
题意:给你n个数字,对于任意s,s满足\(s=u_i+u_j+u_k,i<j<k\),要求出所有的s和对应满足条件的i,j,k的方案数 Solution: 构造一个函数:\(A(x)=\s ...
- 【XSY2753】Lcm 分治 FWT FFT 容斥
题目描述 给你\(n,k\),要你选一些互不相同的正整数,满足这些数的\(lcm\)为\(n\),且这些数的和为\(k\)的倍数. 求选择的方案数.对\(232792561\)取模. \(n\leq ...
- SPOJ - TSUM 母函数+FFT+容斥
题意:n个数,任取三个加起来,问每个可能的结果的方案数. 题解:构造母函数ABC,比如现在有 1 2 3 三个数.则 其中B表示同一个数加两次,C表示用三次.然后考虑去重. A^3表示可重复地拿三个. ...
- SPOJ:Triple Sums(母函数+FFT)
You're given a sequence s of N distinct integers.Consider all the possible sums of three integers fr ...
随机推荐
- XMPP框架下微信项目总结(2)授权登陆/注销/注册/打印日志
xmpp授权登陆步骤1 初始化xmppstream 连接服务器 传递属性jid(IP地址 端口号)2 连接成功后 传递“登”陆密码授权 3 授权后,发送在线消息xmpp所有的代理都是子线程中调用的,处 ...
- Mac 制作 10.11.3 U盘安装盘
U盘要且只分一个区 Mac OS 拓展(日志式) GUID分区表: 将“安装 OS X El Capitan” 放到 应用程序文件夹下 命令: sudo /Applications/Instal ...
- TIME_WAIT连接过多解决办法
问题起因: 自己开发了一个服务器和客户端,通过短连接的方式来进行通讯,由于过于频繁的创建连接,导致系统连接数量被占用,不能及时释放.看了一下18888,当时吓到了. 现象: 1.外部机器不能正常连接S ...
- web.config详解 -- asp.net夜话之十一
1.配置文件节点说明 1.1 <appSettings>节点 1.2 <connectionStrings>节点 1.3 <compilation> ...
- Java并发编程实现概览
并发概览 >>同步 如何同步多个线程对共享资源的访问是多线程编程中最基本的问题之一.当多个线程并发访问共享数据时会出现数据处于计算中间状态或者不一致的问题,从而影响到程序的正确运行.我们通 ...
- 对Cookie和Session的深入理解
session对象 session对象用于存储特定的用户会话所需的信息 . Session对象的引入是为了弥补HTTP协议的不足.HTTP协议本身是无状态的,这与HTTP协议本来的目的是相符的,客户端 ...
- RecyclerView导入依赖包
1. eclipse 上的导入: 如下进入Android SDK的如下路径, \android-sdk\extras\android\m2repository\com\android\support\ ...
- Delphi之DLL知识学习5---在Delphi应用程序中使用DLL
首先说明一下:同一个动态库(DLL)被多个的程序加载的话,那么将会在每次加载的时候都会重新分配新的独立的内存空间,绝对不是共用一个,所以当一个DLL被多次加载的时候,其会在内存中“复制”多份,不会互相 ...
- 【翻译二十二】java-并发之集合与原子变量
Concurrent Collections The java.util.concurrent package includes a number of additions to the Java C ...
- 简简单单的一个PYTHON多进程实现
因为在作自动化部署时,希望能将多个服务分不同的批次进行发布, 同一批次的机器同时发布, 如果前面一批次出错误,后面就需要停止整 个流程. 那可以简单的用threading来实现了. thread_li ...