题目链接:https://open.kattis.com/problems/aplusb
题意:给你一堆数,然后求ai+aj=ak的组成的**(i,j,k)对有多少个**,并且保证i,j,k小标互不相同。
个人感想:
最近在练FFT自己敲的一道题,马蛋数组开小了无限wa了好多次…
首先我们先明确num【k】代表值(i,j)=k的个数,
然后将a[i]+a[i]的那种重复的去掉.
然后再通过再以 a[i]为尾节点k的(i,j,k)有多少种.很明显就是 num【a[i]】种啊,可是有一种情况在于0,因为有可能会自己加了0也等于a[i]所以的特殊处理处0有多少个,减了0就可以了,而且记住,这个(i,j)也是有顺序要求的,(i,j)和(j,i)是2个不同的,所以我们得处理0的时候*2倍.
然后是因为有负数,我们要+M=50000来处理一下就好了.
分析:fft
代码:
/* Author:GavinjouElephant
* Title:
* Number:
* main meanning:
*
*
*
*/
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define lson 2*k
#define rson 2*k+1
typedef long long ll;
const ll INF=0x3f3f3f3f;
const ll maxn=2e5+10;
ll Scan()//读入整数外挂.
{
ll res = 0, ch, flag = 0;
if((ch = getchar()) == '-') //判断正负
flag = 1;
else if(ch >= '0' && ch <= '9') //得到完整的数
res = ch - '0';
while((ch = getchar()) >= '0' && ch <= '9' )
res = res * 10 + ch - '0';
return flag ? -res : res;
}
void Out(ll a) //输出外挂
{
if(a>9)
Out(a/10);
putchar(a%10+'0');
}
const double PI = acos(-1.0);
struct Complex
{
double r,i;
Complex(double _r = 0,double _i = 0)
{
r = _r; i = _i;
}
Complex operator +(const Complex &b)
{
return Complex(r+b.r,i+b.i);
}
Complex operator -(const Complex &b)
{
return Complex(r-b.r,i-b.i);
}
Complex operator *(const Complex &b)
{
return Complex(r*b.r-i*b.i,r*b.i+i*b.r);
}
};
void change(Complex y[],ll len)
{
ll i,j,k;
for(i = 1, j = len/2;i < len-1;i++)
{
if(i < j)swap(y[i],y[j]);
k = len/2;
while( j >= k)
{
j -= k;
k /= 2;
}
if(j < k)j += k;
}
}
void fft(Complex y[],ll len,ll on)
{
change(y,len);
for(ll h = 2;h <= len;h <<= 1)
{
Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
for(ll j = 0;j < len;j += h)
{
Complex w(1,0);
for(ll k = j;k < j+h/2;k++)
{
Complex u = y[k];
Complex t = w*y[k+h/2];
y[k] = u+t;
y[k+h/2] = u-t;
w = w*wn;
}
}
}
if(on == -1)
for(ll i = 0;i < len;i++)
y[i].r /= len;
}
ll a[maxn];
long long num[4*maxn];
long long sum[4*maxn];
Complex x1[4*maxn];
ll n;
const ll M=50000;
int main()
{
scanf("%lld",&n);
memset(num,0,sizeof(num));
ll zero=0;
for(ll i=0;i<n;i++)
{
scanf("%lld",&a[i]);
if(a[i]==0)zero++;
num[a[i]+M]++;
}
sort(a,a+n);
ll len1=(a[n-1]+M)+1;
ll len=1;
while(len<2*len1){len<<=1;}
for(ll i=0;i<len1;i++)
x1[i]=Complex(num[i],0);
for(ll i=len1;i<len;i++)
x1[i]=Complex(0,0);
fft(x1,len,1);
for(ll i = 0;i < len;i++)
x1[i] = x1[i]*x1[i];
fft(x1,len,-1);
for(ll i=0;i<len;i++)
num[i]=(long long)(x1[i].r+0.5);
for(ll i=0;i<n;i++){num[a[i]+a[i]+2*M]--;}
long long res=0;
for(ll i=0;i<n;i++)
{
if(a[i]!=0)
{
res=res+num[a[i]+2*M];
res=res-zero*2;
}
else
{
res=res+num[a[i]+2*M];
res=res-(zero-1)*2;
}
}
printf("%lld\n",res);
return 0;
}