[2017集訓隊作業自選題#119]衆數MAX

題目大意

兩個長度爲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[ij])
還可以把式子變成
ans[i]=nx=1ij=0[A[j]>=x][B[ij]>=x]
不妨設立閾值k,然後先做一遍
ans[i]=kx=1ij=0[A[j]>=x][B[ij]>=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[ij]>kmin(A[j],B[ij])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);
}
發佈了836 篇原創文章 · 獲贊 317 · 訪問量 59萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章