ABC392G
比较经典的生成函数题目。
不难发现题目中 \(B-A=C-B\) 可以化为 \(A+C=2B\)。于是问题转化为:对于一个给定的数 \(k\),在 \(S\) 中选两个数使它们的和为 \(k\)(这个 \(k\) 即是原来的 \(2B\))。
接着读题可以发现,\(S\) 是集合(即 \(S_i\) 互异),\(1 \le S_i \le 10^6\),也就是和不会超过 \(2\times 10^6\)。那么接下来就不难了,可以直接转化为生成函数了。把原来的元素视为 \(x\) 的指数,得到一个多项式:
\[x^{S_1}+x^{S_2}+\cdots+x^{S_n}
\]
将这个多项式平方,幂的乘法相当于指数的加法,所以平方后和为 \(k\) 的方案数即为 \(x^k\) 的系数。直接 FFT 优化即可。
需要注意最后统计总方案时需要去重,设当前系数为 \(g\):
-
\(B+B=2B\),方案数减 \(1\)。
-
当 \(A<C\) 时,\(A+C=2B,C+A=2B\) 都被计算,故要将剩余方案除以 \(2\)。
综上,最终合法的方案数 \(\dfrac{g-1}{2}\)。
设 \(S_i\) 的最大值为 \(m\),则时间复杂度 \(O(m\log m)\)。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const double PI = acos( -1.0 );
struct complex
{
double x,y;
complex ( double x0 = 0 , double y0 = 0 )
{
x = x0,y = y0;
}
}a[4000001];
int n,Li,s[4000001],c[4000001];
long long ans;
complex operator +( complex x , complex y )
{
return complex( x.x + y.x , x.y + y.y );
}
complex operator -( complex x , complex y )
{
return complex( x.x - y.x , x.y - y.y );
}
complex operator *( complex x , complex y )
{
return complex( x.x * y.x - x.y * y.y , x.x * y.y + x.y * y.x );
}
void FFT( complex *A , int flag )
{
for( int i = 0 ; i < Li ; i ++ )
if( i < c[i] )
swap( A[i] , A[c[i]] );
for( int mid = 1 ; mid < Li ; mid <<= 1 )
{
complex Wn;
Wn.x = cos( PI / mid ),Wn.y = flag * sin( PI / mid );
for( int j = 0 ; j < Li ; j += ( mid << 1 ) )
{
complex W;
W.x = 1,W.y = 0;
for( int k = 0 ; k < mid ; k ++ , W = W * Wn )
{
complex x = A[j + k],y = W * A[j + k + mid];
A[j + k] = x + y;
A[j + k + mid] = x - y;
}
}
}
return;
}
int main()
{
cin >> n;
for( int i = 1 ; i <= n ; i ++ )
cin >> s[i],a[s[i]].x = 1;
Li = 1 << 21;
for( int i = 0 ; i < Li ; i ++ )
c[i] = ( c[i >> 1] >> 1 ) | ( ( i & 1 ) << 20 );
FFT( a , 1 );
for( int i = 0 ; i < Li ; i ++ )
a[i] = a[i] * a[i];
FFT( a , -1 );
for( int i = 0 ; i < Li ; i ++ )
a[i].x = int( a[i].x / ( Li * 1.0 ) + 0.5 );
for( int i = 1 ; i <= n ; i ++ )
ans += ( a[s[i] * 2].x - 1 ) / 2;
cout << ans;
return 0;
}

浙公网安备 33010602011771号