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;
}
posted @ 2025-09-08 18:43  FormulaOne  阅读(9)  评论(0)    收藏  举报