题目大意
两个长度为n的序列a和b,将它们分别任意排列,然后令
c[i]=a[i]+b[i]
,使c[i]的众数出现次数尽量多。
值域与n同阶。
做法
不妨令A[i]表示a中i的出现次数,B同理。
令ans[i]表示i作为众数的最多出现次数。
显然的暴力
ans[i]=∑ij=0min(A[j],B[i−j])
还可以把式子变成
ans[i]=∑nx=1∑ij=0[A[j]>=x]∗[B[i−j]>=x]
不妨设立阈值k,然后先做一遍
ans[i]=∑kx=1∑ij=0[A[j]>=x]∗[B[i−j]>=x]
可以设
c[i]=[A[i]>=x]
,
d[i]=[B[i]>=x]
,可以发现可以用FFT来计算c和d的卷积。
这里复杂度为O(nk log n)。
然后接下来做一遍
ans[i]=∑ij=0,A[j]>k,B[i−j]>kmin(A[j],B[i−j])−k
这里复杂度为O(n^2/k^2)。
取k=10比较优秀。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef double db;
const int maxlen=100000*5+10,B=10;
const db pi=acos(-1);
int rev[maxlen];
struct node{
db x,y;
friend node operator +(node a,node b){
node c;
c.x=a.x+b.x;
c.y=a.y+b.y;
return c;
}
friend node operator -(node a,node b){
node c;
c.x=a.x-b.x;
c.y=a.y-b.y;
return c;
}
friend node operator *(node a,node b){
node c;
c.x=a.x*b.x-a.y*b.y;
c.y=a.x*b.y+a.y*b.x;
return c;
}
};
node w[maxlen],c[maxlen],d[maxlen],tt[maxlen];
int ans[maxlen],a[maxlen],b[maxlen],s1[maxlen],s2[maxlen];
int i,j,k,l,t,n,m,N,mx,len,tot,top;
db ce;
void prepare(){
fo(i,0,len-1){
int p=0;
for(int j=0,tp=i;j<ce;j++,tp/=2) p=(p<<1)+(tp%2);
rev[i]=p;
}
w[0].x=1;w[0].y=0;
w[1].x=cos(2*pi/len);w[1].y=sin(2*pi/len);
fo(i,2,len) w[i]=w[i-1]*w[1];
}
void DFT(node *a,int sig){
int i;
fo(i,0,len-1) tt[rev[i]]=a[i];
for(int m=2;m<=len;m*=2){
int half=m/2,bei=len/m;
fo(i,0,half-1){
node wi=sig>0?w[i*bei]:w[len-i*bei];
for(int j=i;j<len;j+=m){
node u=tt[j],v=tt[j+half]*wi;
tt[j]=u+v;
tt[j+half]=u-v;
}
}
}
if (sig==-1)
fo(i,0,len-1) tt[i].x/=len;
fo(i,0,len-1) a[i]=tt[i];
}
void FFT(){
int i;
DFT(c,1);
DFT(d,1);
fo(i,0,len-1) c[i]=c[i]*d[i];
DFT(c,-1);
}
int main(){
scanf("%d",&n);
N=n;
fo(i,1,n){
scanf("%d",&t);
N=max(N,t);
a[t]++;
}
fo(i,1,n){
scanf("%d",&t);
N=max(N,t);
b[t]++;
}
len=1;
//N=100000;
while (len<=N*2) len*=2;
ce=log(len)/log(2);
prepare();
fo(i,1,B){
fo(j,0,len-1)
c[j].x=c[j].y=d[j].x=d[j].y=0;
fo(j,0,len-1){
c[j].x=(a[j]>=i);
d[j].x=(b[j]>=i);
}
FFT();
fo(j,0,len-1) ans[j]+=int(round(c[j].x));
}
fo(i,0,len-1){
if (a[i]>B) s1[++tot]=i;
if (b[i]>B) s2[++top]=i;
}
fo(i,1,tot)
fo(j,1,top)
ans[s1[i]+s2[j]]+=min(a[s1[i]],b[s2[j]])-B;
fo(i,0,len-1) mx=max(mx,ans[i]);
printf("%d\n",mx);
}