1. 程式人生 > 其它 >NOIP 模擬 $22\; \rm f$

NOIP 模擬 $22\; \rm f$

題解

題解 \(by\;zj\varphi\)

對於一個數,如果它二進位制下第 \(i\) 位為 \(1\),那麼 \(\rm x\) 在這一位選 \(1\) 的貢獻就是和它不同的最高為為 \(i\) 的數的個數

這個東西很好搞,整一個 \(\rm 01trie\) 就行,每會插入的時候直接統計即可

但是如何求第 \(p\) 位,二分,但每回二分時 \(2^k\) 搜尋一遍就超時了,\(\rm meet\;in\;the\;middle\)

發現每一位是相互獨立的,也就是說它們之間是不會互相影響的,所以將二進位制位割半,分別排個序,之後對於一個序列用指標從小往大搜,同時維護另一個指標,而這個指標一定是單調遞減的;

所以複雜度就是 \(2^\frac{k}{2}log\frac{n×(n-1)}{2}\)

對於第二問,對於大的那一半開個桶,維護它能在小的那一半匹配上的數,最後按大的排序,跳區間,每次判斷這個數匹配上的 \(siz\) 是否大於 \(p\),若大於就在區間內暴力,可以保證複雜度不會超過 \(2^\frac{k}{2}\)

所以總複雜度為 \(\mathcal O\rm (nk+2^\frac{k}{2}log\frac{n×(n-1)}{2}+2^\frac{k}{2})\)

Code
#include<bits/stdc++.h>
#define ri register signed
#define p(i) ++i
using namespace std;
namespace IO{
    char buf[1<<21],*p1=buf,*p2=buf;
    #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++
    template<typename T>inline void read(T &x) {
        ri f=1;x=0;register char ch=gc();
        while(ch<'0'||ch>'9') {if (ch=='-') f=0;ch=gc();}
        while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        x=f?x:-x;
    }
}
using IO::read;
namespace nanfeng{
    #define pb(x) push_back(x)
    #define FI FILE *IN
    #define FO FILE *OUT
    template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
    template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
    typedef long long ll;
    static const int N=5e5+7;
    int a[N],tmp[N],st[N],pg[1<<16],id[1<<16],cnt1,cnt2,cnt,n,k,p,mx,hk,kh,S1,S2,bs,num,ans;
    ll al,del[33];
    vector<int> sg[1<<16];
    struct slv{ll f;int id;}so1[1<<16],so2[1<<16];
    inline int operator<(const slv &s1,const slv &s2) {return s1.f<s2.f;}
    struct BIT{
        #define lowbit(x) ((x)&-(x))
        int c[N];
        inline void update(int x) {for (ri i(x);i<=mx;i+=lowbit(i)) p(c[i]);}
        inline int query(int x) {
            int res(0);
            for (ri i(x);i;i-=lowbit(i)) res+=c[i];
            return res;
        }
    }B;
    struct Trie{
        #define sn(x,u) T[x].ch[u]   
        struct trie{int ch[2],sz;}T[N*30];
        int tot;
        Trie(){tot=1;}
        inline void insert(int nw) {
            int p=1;
            for (ri i(29);~i;--i) {
                ri cur=(nw>>i)&1;
                if (!cur) del[i]-=T[sn(p,cur^1)].sz;
                else del[i]+=T[sn(p,cur^1)].sz;
                if (!sn(p,cur)) sn(p,cur)=p(tot);
                p=sn(p,cur);
                p(T[p].sz);
            }
        }
    }T;
    inline void init() {
        sort(tmp+1,tmp+n+1);
        int k=unique(tmp+1,tmp+n+1)-tmp;
        for (ri i(1);i<=n;p(i)) st[i]=lower_bound(tmp+1,tmp+k,st[i])-tmp;
        mx=k-1;
        for (ri i(n);i;--i) {
            al+=B.query(st[i]-1);
            B.update(st[i]);
        }
    }
    inline int check(ll f) {
        ri p2=1;
        num=0;
        for (ri p1(cnt1);p1;--p1) {
            while(p2<=cnt2&&so2[p2].f+so1[p1].f+al<=f) p(p2);
            num+=p2-1;
        }
        return num>=p;
    }
    inline void checka(ll f) {
        ri p1=1,tmp;
        num=0;
        for (ri p2(cnt2);p2;--p2) {
            p(cnt);
            id[pg[cnt]=cnt]=so2[p2].id;
            while(p1<=cnt1&&so2[p2].f+so1[p1].f+al<f) p(p1);
            tmp=0;
            while(p1<=cnt1&&so2[p2].f+so1[p1].f+al==f) {
                p(tmp);
                sg[cnt].pb(so1[p1].id);
                p(p1);
            }
            num+=p1-1-tmp;
        }
    }
    inline int cmp(int x,int y) {return id[x]<id[y];}
    inline int main() {
        // FI=freopen("nanfeng.in","r",stdin);
        // FO=freopen("nanfeng.out","w",stdout);
        read(n),read(k),read(p);
        for (ri i(1);i<=n;p(i)) read(a[i]),st[i]=tmp[i]=a[i];
        init();
        for (ri i(1);i<=n;p(i)) T.insert(a[i]);
        hk=k>>1,kh=k-hk;
        bs=(S1=(1<<hk)-1)+1;
        S2=((1<<kh)-1)<<hk;
        for (ri i(0);i<=S1;p(i)) {
            ll tmp=0;
            for (ri j(0);j<hk;p(j)) if ((i>>j)&1) tmp+=del[j];
            so1[p(cnt1)].f=tmp;
            so1[cnt1].id=i;
        }
        for (ri i(0);i<=S2;i+=bs) {
            ll tmp=0;
            for (ri j(hk);j<k;p(j)) if ((i>>j)&1) tmp+=del[j];
            so2[p(cnt2)].f=tmp;
            so2[cnt2].id=i;
        }
        sort(so1+1,so1+cnt1+1); 
        sort(so2+1,so2+cnt2+1);
        ll l=0,r=(ll)n*(n-1)/2,res(0);
        while(l<=r) {
            ll mid=(l+r>>1ll);
            if (check(mid)) r=mid-1,res=mid;
            else l=mid+1;
        }
        checka(res);
        sort(pg+1,pg+cnt+1,cmp);
        p-=num;
        for (ri i(1);i<=cnt;p(i)) {
            int cur=pg[i],siz=sg[cur].size();
            if (p>siz) p-=siz; 
            else {
                sort(sg[cur].begin(),sg[cur].end());
                ans=id[cur]|sg[cur][p-1]; 
                break;
            }
        }
        printf("%lld %d\n",res,ans);
        return 0;
    }  
}
int main() {return nanfeng::main();}