[SP8372-TSUM]Triple Sums

本文介绍了一种使用生成函数解决特定组合问题的方法:给定一系列正整数,求解满足条件的三元组数量,并对所有可能的三元组和进行计数。

题面在这里

description

\(B\)\(OJ\)权限题
给出\(n\)个正整数\(a[i]\),求\(i<j<k\)\(S=a[i]+a[j]+a[k]\)的三元组\((i,j,k)\)的个数
需要对所有可能的\(S\)进行求解

data range

\[n\le 40000,|a[i]|\le 20000\]

solution

考虑构造生成函数求解
构造\(A(x)=\sum_{i=1}^{n}x^{a[i]},B(x)=\sum_{i=1}^{n}x^{2\times a[i]},C(x)=\sum_{i=1}^{n}x^{3\times a[i]}\)
然后容斥:\[f(x)=\frac{A(x)^3-3A(x)B(x)+2C(x)}{6}\]

code

这里本人写得复杂

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define FILE "a"
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=1e9+7;
const int N=1000010;
const dd pi=acos(-1);
const int inf=2147483647;
const ll INF=1e18+1;
il ll read(){
    RG ll data=0,w=1;RG char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
    return data*w;
}

il void file(){
    srand(time(NULL)+rand());
    freopen(FILE".in","r",stdin);
    freopen(FILE".out","w",stdout);
}

struct point{dd r,i;}a[N],b[N];
il point operator +(point a,point b){return (point){a.r+b.r,a.i+b.i};}
il point operator -(point a,point b){return (point){a.r-b.r,a.i-b.i};}
il point operator *(point a,point b){
    return (point){a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r};
}

int r[N],l;
il void FFT(point *a,int n,int opt){
    for(RG int i=0;i<n;i++)if(i<r[i])swap(a[i],a[r[i]]);
    for(RG int i=2;i<=n;i<<=1){
        point wn=(point){cos(2*pi/i),opt*sin(2*pi/i)};
        for(RG int j=0;j<n;j+=i){
            point w=(point){1,0};
            for(RG int k=j;k<j+(i>>1);k++,w=w*wn){
                point x=a[k+(i>>1)]*w;
                a[k+(i>>1)]=a[k]-x;
                a[k]=a[k]+x;
            }
        }
    }
    if(opt==-1)for(RG int i=0;i<n;i++)a[i].r/=n;
}

int n,lim,m,len,A[N];ll f[N],g[N],h[N];
int main()
{
    n=read();lim=inf;m=120000;for(len=1,l=0;len<=m;len<<=1,l++);
    for(RG int i=0;i<len;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    for(RG int i=1;i<=n;i++)A[i]=read();lim=-20000;
    for(RG int i=1;i<=n;i++){
        f[A[i]-lim]++;g[2*A[i]-2*lim]++;h[3*A[i]-3*lim]++;
    }
    for(RG int i=0;i<len;i++)a[i].r=g[i],b[i].r=f[i];
    FFT(a,len,1);FFT(b,len,1);
    for(RG int i=0;i<len;i++)a[i]=a[i]*b[i];
    FFT(a,len,-1);
    for(RG int i=0;i<len;i++)g[i]=(ll)(a[i].r+0.5);

    for(RG int i=0;i<len;i++)a[i].r=f[i],a[i].i=0;
    FFT(a,len,1);
    for(RG int i=0;i<len;i++)a[i]=a[i]*a[i]*a[i];
    FFT(a,len,-1);
    for(RG int i=0;i<len;i++)f[i]=(ll)(a[i].r+0.5);
    
    for(RG int i=0;i<=m;i++)
        if((f[i]-3*g[i]+2*h[i])/6>0)
            printf("%d : %lld\n",i+3*lim,(f[i]-3*g[i]+2*h[i])/6);
    return 0;
}

转载于:https://www.cnblogs.com/cjfdf/p/9156249.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值