[BZOJ3771] Triple 题解

《关于贫穷的樵夫拥有 40000 把斧头这件事》。


相当于是多项式乘法,但是得带容斥,具体自己看代码吧。

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
const long double pi=acos(-1);
namespace FFT{
    int rev[N],mx,k;
    struct comn{long double a,b;};
    struct dft{comn fg[N];};
    comn operator+(comn x,comn y){
        return {x.a+y.a,x.b+y.b};
    }comn operator-(comn x,comn y){
        return {x.a-y.a,x.b-y.b};
    }comn operator*(comn x,comn y){
        return {x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a};
    }void operator+=(comn &x,comn y){x=x+y;}
    void operator-=(comn &x,comn y){x=x-y;}
    void operator*=(comn &x,comn y){x=x*y;}
    void init(int n){
        mx=1,k=0,rev[0]=0;
        while(mx<=n) mx*=2,k++;
        for(int i=0;i<mx;i++)
            rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
    }void fft(dft &a,int fl){
        for(int i=0;i<mx;i++)
            if(i<rev[i]) swap(a.fg[i],a.fg[rev[i]]);
        comn o={cos(pi),fl*sin(pi)},w={1,0};
        for(int i=1;i<mx;i*=2,o={cos(pi/i),fl*sin(pi/i)})
            for(int j=0;j<mx;j+=i*2,w={1,0})
                for(int l=j;l<j+i;l++){
                    comn x=a.fg[l],y=w*a.fg[l+i];
                    a.fg[l]+=y,a.fg[l+i]=x-y,w*=o;
                }
    }void operator+=(dft &x,dft &y){
        for(int i=0;i<mx;i++) x.fg[i]+=y.fg[i];
    }void operator-=(dft &x,dft &y){
        for(int i=0;i<mx;i++) x.fg[i]-=y.fg[i];
    }
}using namespace FFT;
int n,ans[N],sum[N],sm[N],m;dft al,be,th,de;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0),cin>>n;
    for(int i=1,x;i<=n;i++){
        cin>>x,al.fg[x].a++,be.fg[x*2].a++;
        m=max(m,x),ans[x]++,sum[x*2]++,sm[x*3]++;
    }m*=3,init(m+1),fft(al,1),fft(be,1);
    for(int i=0;i<mx;i++){
        th.fg[i]=al.fg[i]*al.fg[i];
        de.fg[i]=al.fg[i]*be.fg[i];
    }fft(th,-1),fft(de,-1);
    for(int i=1;i<=m;i++){
        ans[i]+=(int)((th.fg[i].a-sum[i])/2/mx+0.5);
        sm[i]+=((int)(de.fg[i].a/mx+0.5)-sm[i])*3;
    }for(int i=1;i<=m;i++) th.fg[i].a/=mx;
    fft(th,1);
    for(int i=0;i<mx;i++)
        th.fg[i]*=al.fg[i];
    fft(th,-1);
    for(int i=1;i<=m;i++)
        ans[i]+=((int)(th.fg[i].a/mx+0.5)-sm[i])/6;
    for(int i=1;i<=m;i++)
        if(ans[i]) cout<<i<<" "<<ans[i]<<"\n";
    return 0;
}
posted @   长安一片月_22  阅读(3)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
历史上的今天:
2024-01-19 [BZOJ3786] 星系探索 题解
2024-01-19 [JSOI2008]火星人 题解
点击右上角即可分享
微信分享提示