Topcoder SRM 603 Div1 1000 :Sum Of Arrays (FFT)

本文探讨了一种特殊的数组配对求和问题,通过优化算法实现尽可能多地产生相等的和值。介绍了一种结合快速傅立叶变换(FFT)与暴力匹配的方法,并给出具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hero has two arrays of integers: A and B. Each of the arrays contains exactly n elements.
Hero will do two things with his arrays: First, he will permute the elements in each of his arrays somehow. (He is allowed to put the elements of each array into any order he likes, including their original order. He is not allowed to swap elements between A and B, each array has to be rearranged separately.) Afterwards, he will produce a new array C of n elements such that for all i, C[i] = A[i] + B[i].
Hero likes equal numbers. His goal is to produce as many equal numbers in C as possible. Formally, for a given C he is interested in integers X and Y such that the array C contains X occurrences of the value Y, and X is as large as possible.

题解:
其实就是让你求这玩意儿:

maxcici=j=0nmin{aj,bij}maxcici=∑j=0nmin{aj,bi−j}

其中aiaiiiA数组中的出现次数,
这个式子一般情况下是不能FFTFFT的,不过观察到aab所有数加起来也不过nn个,我们可以分段解决。
L为阀值,小于LL的位置我们做LFFTFFT,大于LL的直接暴力匹配,复杂度为:O(Lnlogn+(nL)2)
L=(nlogn)31L=(nlog⁡n)31时最优,复杂度为O(n43log23n)O(n43log23⁡n)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e6+50,L=20,mod=998244353,G=3;
inline int add(int x,int y) {return (x+y>=mod)?(x+y-mod):(x+y);}
inline int dec(int x,int y) {return (x-y<0)?(x-y+mod):(x-y);}
inline int mul(int x,int y) {return (LL)x*y%mod;}
inline int power(int a,int b) {
    int rs=1;
    for(;b;b>>=1, a=mul(a,a)) if(b&1) rs=mul(rs,a);
    return rs;
}
int k,a[N],b[N],c[N],ca[N],cb[N],cc[N],ta[N],tb[N],tc[N],pos[N],w[N],mx;
inline void init(int len) {
    for(k=1;k<=len;k<<=1);
    for(int i=1;i<k;i++) pos[i]=(i&1)?((pos[i>>1]>>1)^(k>>1)):(pos[i>>1]>>1);
}
inline void dft(int *a) {
    for(int i=1;i<k;i++) if(pos[i]>i) swap(a[pos[i]],a[i]);
    for(int bl=1;bl<k;bl<<=1) {
        int tl=bl<<1, wn=power(G,(mod-1)/tl); w[0]=1;
        for(int i=1;i<bl;i++) w[i]=mul(w[i-1],wn);
        for(int bg=0;bg<k;bg+=tl)
            for(int j=0;j<bl;j++) {
                int &t1=a[bg+j], &t2=a[bg+j+bl], t=mul(t2,w[j]);
                t2=dec(t1,t); t1=add(t1,t);
            }
    }
}
inline void calc() {
    for(int i=0;i<k;i++) ta[i]=tb[i]=0;
    for(int i=0;i<=mx;i++) ta[i]=(ca[i]?(--ca[i],1):0), tb[i]=(cb[i]?(--cb[i],1):0);
    for(int i=mx+1;i<k;i++) ta[i]=tb[i]=0;
    dft(ta); dft(tb); const int inv=power(k,mod-2);
    for(int i=0;i<k;i++) tc[i]=mul(ta[i],tb[i]);
    dft(tc); reverse(tc+1,tc+k);
    for(int i=0;i<k;i++) cc[i]+=mul(tc[i],inv);
}
inline string tostring(int x) {
    static int buf[50];
    string t; 
    if(!x) {return "0";}
    while(x) {buf[++buf[0]]=x%10; x/=10;}
    while(buf[0]) t+=char('0'+buf[buf[0]--]);
    return t;
}
class SumOfArrays {
    public:
    string findbestpair(int n, vector<int> Aseed, vector<int> Bseed) {
        a[0]=Aseed[0]; a[1]=Aseed[1]; b[0]=Bseed[0]; b[1]=Bseed[1]; 
        for(int i=2;i<n;i++) {
            a[i]=((LL)a[i-1]*Aseed[2]+(LL)a[i-2]*Aseed[3]+Aseed[4])%Aseed[5];
            b[i]=((LL)b[i-1]*Bseed[2]+(LL)b[i-2]*Bseed[3]+Bseed[4])%Bseed[5];
        }
        mx=*max_element(a,a+n)+*max_element(b,b+n); init(mx);
        for(int i=0;i<n;i++) ca[a[i]]++, cb[b[i]]++;
        for(int i=1;i<=L;i++) 
            calc();
        ta[0]=0; tb[0]=0;
        for(int i=0;i<=mx;i++) {
            if(ca[i]) ta[++ta[0]]=i;
            if(cb[i]) tb[++tb[0]]=i;
        }
        for(int i=ta[0];i;i--)
            for(int j=tb[0];j;j--)
                cc[ta[i]+tb[j]]=add(cc[ta[i]+tb[j]],min(ca[ta[i]],cb[tb[j]]));
        int ans=0;
        for(int i=0;i<=mx;i++)
            if(cc[ans]<=cc[i]) ans=i;
        return tostring(cc[ans])+" "+tostring(ans);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值