提交记录 85052


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_codex_maker test. 自定义测试 Accepted 100 6.605 s 900156 KB C++17 7.55 KB
提交时间 评测时间
2026-09-23 00:17:27 2026-09-23 00:17:36
// Original implementation for these contribution packages, C++11 or later.
// Exact strict dominance: rank is a position; lower is the first position
// of the coordinate's equal-value group. No input array is modified.
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <vector>
#include <immintrin.h>
#pragma GCC target("avx2,popcnt")

namespace dominance {
using U = unsigned;
using W = unsigned long long;

template<int K> struct AndWords {
    static inline __m256i get(const W *const *p, U w) {
        return _mm256_and_si256(AndWords<K-1>::get(p,w),
            _mm256_loadu_si256((const __m256i*)(p[K-1]+w)));
    }
    static inline W scalar(const W *const *p, U w) {
        return AndWords<K-1>::scalar(p,w) & p[K-1][w];
    }
};
template<> struct AndWords<1> {
    static inline __m256i get(const W *const *p,U w) {
        return _mm256_loadu_si256((const __m256i*)(p[0]+w));
    }
    static inline W scalar(const W *const *p,U w) { return p[0][w]; }
};
template<int K> static U intersection(const W *const *p,U bits) {
    const __m256i lut=_mm256_setr_epi8(0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
                                      0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4);
    const __m256i mask=_mm256_set1_epi8(15);
    __m256i acc=_mm256_setzero_si256();
    U w=0,full=bits/64,ans=0;
    for(;w+4<=full;w+=4) {
        __m256i v=AndWords<K>::get(p,w);
        __m256i lo=_mm256_shuffle_epi8(lut,_mm256_and_si256(v,mask));
        __m256i hi=_mm256_shuffle_epi8(lut,_mm256_and_si256(_mm256_srli_epi16(v,4),mask));
        acc=_mm256_add_epi64(acc,_mm256_sad_epu8(_mm256_add_epi8(lo,hi),_mm256_setzero_si256()));
    }
    W sums[4];_mm256_storeu_si256((__m256i*)sums,acc);
    ans=U(sums[0]+sums[1]+sums[2]+sums[3]);
    for(;w<full;++w) ans+=__builtin_popcountll(AndWords<K>::scalar(p,w));
    if(bits%64) ans+=__builtin_popcountll(AndWords<K>::scalar(p,full)&((1ULL<<(bits%64))-1));
    return ans;
}

template<int D> void count(int n,const U *const *x,U *out) {
    if(n<=0) return;
    const U nn=U(n), words=(nn+63)/64;
    const U block=nn<=100000?64:nn<=300000?128:D<=5?256:512;
    std::vector<U> ord[D],rank[D],lower[D],hist(size_t(nn)+1),owner(nn);
    for(int d=0;d<D;++d) {
        ord[d].resize(nn);rank[d].resize(nn);lower[d].resize(nn);
        std::fill(hist.begin(),hist.end(),0);
        for(U i=0;i<nn;++i) ++hist[x[d][i]+1];
        for(U v=1;v<=nn;++v) hist[v]+=hist[v-1];
        for(U i=0;i<nn;++i) lower[d][i]=hist[x[d][i]];
        for(U i=0;i<nn;++i) ord[d][hist[x[d][i]]++]=i;
        for(U p=0;p<nn;++p) rank[d][ord[d][p]]=p;
    }
    for(U i=0;i<nn;++i) {
        U a=0;for(int d=1;d<D;++d) if(lower[d][i]<lower[a][i]) a=d;
        owner[i]=a;out[i]=0;
    }
    // Row e stores the first ceil(min(n,(e+1)*block)/64) bits.
    // Each query owned by a has lower[a] <= lower[d], so this is enough.
    const U blocks=(nn+block-1)/block;
    std::vector<size_t> off(blocks+2,0);
    for(U e=0;e<=blocks;++e) {
        size_t len=(std::min(nn,(e+1)*block)+63)/64;
        off[e+1]=off[e]+((len+7)&~size_t(7));
    }
    for(int a=0;a<D;++a) {
        bool used=false;
        for(U i=0;i<nn;++i) if(owner[i]==U(a) && lower[a][i]) {used=true;break;}
        if(!used) continue;
        const int sweep=(a+1)%D;
        int dims[D-2],nd=0;
        for(int d=0;d<D;++d) if(d!=a && d!=sweep) dims[nd++]=d;
        const int PAD=(D+3)/4*4;
        std::vector<U> records[D-2];
        std::vector<W> table[D-2],active(words,0),running(words,0);
        for(int k=0;k<D-2;++k) {
            int d=dims[k];table[k].resize(off.back());
            records[k].resize(size_t(nn)*PAD,0);
            for(U z=0;z<nn;++z) {
                U j=ord[d][z];
                U *r=records[k].data()+size_t(z)*PAD;
                r[0]=rank[a][j];r[1]=rank[sweep][j];
                for(int h=0;h<D-2;++h) r[h+2]=rank[dims[h]][j];
            }
            std::fill(running.begin(),running.end(),0);
            for(U p=0;p<=nn;++p) {
                if(p%block==0) {
                    U e=p/block;
                    size_t len=(std::min(nn,(e+1)*block)+63)/64;
                    std::memcpy(table[k].data()+off[e],running.data(),len*sizeof(W));
                }
                if(p==nn) break;
                U r=rank[a][ord[d][p]];running[r/64]|=1ULL<<(r%64);
            }
            if(nn%block) std::memcpy(table[k].data()+off[blocks],running.data(),words*sizeof(W));
        }
        U inserted=0;
        for(U pos=0;pos<nn;++pos) {
            U q=ord[sweep][pos];
            if(owner[q]!=U(a) || lower[a][q]==0) continue;
            U ta=lower[a][q],ts=lower[sweep][q],t[D-2],boundary[D-2];
            while(inserted<ts) {
                U r=rank[a][ord[sweep][inserted++]];active[r/64]|=1ULL<<(r%64);
            }
            const W *p[D-1];p[0]=active.data();
            for(int k=0;k<D-2;++k) {
                t[k]=lower[dims[k]][q];
                U e=(t[k]+block/2)/block;
                boundary[k]=std::min(nn,e*block);
                p[k+1]=table[k].data()+off[e];
            }
            long long ans=intersection<D-1>(p,ta);
            // Replace one rounded boundary at a time. Earlier dimensions
            // use exact bounds; later dimensions still use rounded bounds.
            for(int k=0;k<D-2;++k) {
                U limits[PAD];std::fill(limits,limits+PAD,nn);
                limits[0]=ta;limits[1]=ts;
                for(int h=0;h<D-2;++h) if(h!=k) limits[h+2]=h<k?t[h]:boundary[h];
                U lo=std::min(t[k],boundary[k]),hi=std::max(t[k],boundary[k]),count=0;
                if(PAD==4) {
                    __m128i v=_mm_loadu_si128((const __m128i*)limits);
                    for(U z=lo;z<hi;++z) {
                        __m128i r=_mm_loadu_si128((const __m128i*)(records[k].data()+size_t(z)*PAD));
                        count+=_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpgt_epi32(v,r)))==15;
                    }
                } else {
                    __m256i v=_mm256_loadu_si256((const __m256i*)limits);
                    for(U z=lo;z<hi;++z) {
                        const U *r=records[k].data()+size_t(z)*PAD;
                        __m256i m=_mm256_cmpgt_epi32(v,_mm256_loadu_si256((const __m256i*)r));
                        if(_mm256_movemask_ps(_mm256_castsi256_ps(m))!=255) continue;
                        if(PAD>8) {
                            __m128i v2=_mm_loadu_si128((const __m128i*)(limits+8));
                            __m128i r2=_mm_loadu_si128((const __m128i*)(r+8));
                            if(_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpgt_epi32(v2,r2)))!=15) continue;
                        }
                        ++count;
                    }
                }
                ans+=t[k]>=boundary[k]?static_cast<long long>(count):-static_cast<long long>(count);
            }
            out[q]=U(ans);
        }
    }
}
} // namespace dominance

#include <cassert>
#include <cstdio>
static unsigned long long state=0x7145aa819275cdefULL;
static unsigned rnd() {state+=0x9e3779b97f4a7c15ULL;unsigned long long z=state;z=(z^(z>>30))*0xbf58476d1ce4e5b9ULL;z=(z^(z>>27))*0x94d049bb133111ebULL;return unsigned(z^(z>>31));}
int main() {
    const int D=5,N=1000000;
    std::vector<unsigned> coords[D],out(N);
    const unsigned *x[D];
    for(int d=0;d<D;++d) {coords[d].resize(N);x[d]=coords[d].data();for(int i=0;i<N;++i) coords[d][i]=rnd()%N;}
    dominance::count<5>(N,x,out.data());
    for(int q=0;q<32;++q) {unsigned i=rnd()%N,want=0;
        for(int j=0;j<N;++j) {bool ok=true;for(int d=0;d<D;++d) if(x[d][j]>=x[d][i]) {ok=false;break;} want+=ok;}
        assert(out[i]==want);
    }
    std::puts("dominance benchmark: 32 sampled answers checked");
}

CompilationN/AN/ACompile OKScore: N/A

Testcase #16.605 s879 MB + 60 KBAcceptedScore: 100


Judge Duck Online | 评测鸭在线
Server Time: 2026-09-24 03:57:46 | Loaded in 0 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠