1 条题解

  • 0
    @ 2025-4-7 23:24:36

    题意分析

    用完全有向图表示,每个顶点代表一个玩家 边xyx \rightarrow y表示玩家xx击败玩家yy

    玩家xx的得分sxs_x是被xx击败的玩家数量 得分序列S(T)=(s1,s2,...,sn)S(T)=(s_1,s_2,...,s_n)是所有玩家得分的非递减排序 玩家xx是强王,当且仅当xx击败了所有得分比xx高的玩家 即:对于所有sy>sxs_y > s_x,存在边xyx \rightarrow y 在所有实现给定得分序列SS的锦标赛中,拥有最多强王的锦标赛

    问题要求

    给定一个得分序列SS,找出重型锦标赛中强王的最大可能数量。

    解题思路

    关键观察

    必须满足i=1ksi(k2)\sum_{i=1}^k s_i \geq \binom{k}{2},对所有1kn1 \leq k \leq nk=nk=n时,i=1nsi=(n2)\sum_{i=1}^n s_i = \binom{n}{2} 对玩家xx,检查是否击败了所有sy>sxs_y > s_x的玩家 得分相同的玩家之间胜负不影响强王判定 需要合理安排同分玩家之间的胜负关系 高得分玩家应尽可能被多个低得分玩家击败

    算法设计

    将得分序列SS排序(非递减) 统计每个得分的出现次数 从高得分到低得分处理: 最高得分玩家自动成为强王 对每个得分ss,计算可以有多少玩家满足: 击败所有>s>s的玩家 不被同分或更低分玩家影响

    贪心策略: 让尽可能多的玩家满足强王条件 同分玩家之间构造循环胜负(如A→B→C→A) 低分玩家必须击败所有高分玩家

    复杂度分析

    时间:O(n2)O(n^2),需要检查每个玩家对其他玩家的胜负关系 空间:O(n)O(n),存储得分序列和统计信息

    标程

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    
    const int MAXN = 1e3+5;
    const int INF = 0x3f3f3f3f;
    typedef long long LL;
    
    struct lp{
        int to,nex,cap,flow;
    }cw[MAXN*10];
    int tol;
    int head[MAXN];
    int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
    int n,m;
    int ar[MAXN],mp[MAXN][MAXN];
    char tools[100000];
    
    void init(){
        tol = 0;
        // 手动初始化 head 数组
        for (int i = 0; i < MAXN; ++i) {
            head[i] = -1;
        }
    }
    
    void add(int u,int v,int w,int rw = 0){
        cw[tol].to = v;
        cw[tol].cap = w;
        cw[tol].nex = head[u];
        cw[tol].flow = 0;
        head[u] = tol++;
        cw[tol].to = u;
        cw[tol].cap = rw;
        cw[tol].nex = head[v];
        cw[tol].flow = 0;
        head[v] = tol++;
    }
    
    int sap(int start,int end,int N){
        // 手动初始化 gap 数组
        for (int i = 0; i < MAXN; ++i) {
            gap[i] = 0;
        }
        // 手动初始化 dep 数组
        for (int i = 0; i < MAXN; ++i) {
            dep[i] = 0;
        }
        // 手动复制 head 数组到 cur 数组
        for (int i = 0; i < MAXN; ++i) {
            cur[i] = head[i];
        }
        int u = start;
        pre[u] = -1;
        gap[0] = N;
        int ans = 0;
        while(dep[start] < N){
            if(u == end){
                int Min = INF;
                for(int i = pre[u]; i != -1;i = pre[cw[i^1].to])
                    if(Min > cw[i].cap - cw[i].flow)
                        Min = cw[i].cap - cw[i].flow;
                for(int i = pre[u];i != -1;i = pre[cw[i^1].to]){
                    cw[i].flow += Min;
                    cw[i^1].flow -= Min;
                }
                u = start;
                ans += Min;
                continue;
            }
            bool flag = false;
            int v;
            for(int i = cur[u];i != -1;i = cw[i].nex){
                v = cw[i].to;
                if(cw[i].cap - cw[i].flow && dep[v] + 1 == dep[u]){
                    flag = true;
                    cur[u] = pre[v] = i;
                    break;
                }
            }
            if(flag){
                u = v;
                continue;
            }
            int Min = N;
            for(int i = head[u];i != -1;i = cw[i].nex)
                if(cw[i].cap - cw[i].flow && dep[cw[i].to] < Min){
                    Min = dep[cw[i].to];
                    cur[u] = i;
                }
            gap[dep[u]]--;
            if(!gap[dep[u]])return ans;
            dep[u] = Min+1;
            gap[dep[u]]++;
            if(u != start)u = cw[pre[u]^1].to;
        }
        return ans;
    }
    
    int build(int k){
        init();
        int vs=0,vt=m+1;
        for(int i=1;i<=n;++i){
            add(vs,i,ar[i]);
            for(int j=i+1;j<=n;++j){
                if(i>=n-k+1&&ar[i]<ar[j]){
                    add(i,mp[i][j],1);
                }else{
                    add(i,mp[i][j],1);
                    add(j,mp[i][j],1);
                }
                add(mp[i][j],vt,1);
            }
        }
        return sap(vs,vt,vt+1);
    }
    
    void cut(char *s){
        int len = strlen(s);  
        int t = 0;
        for(int i = 0; i < len; i++){
            if(s[i] >= '0' && s[i] <= '9'){
                t = t * 10 + s[i] - '0';
                if(i == len - 1 || s[i + 1] == ' '){
                    ar[++n] = t;  
                    t = 0;  
                }  
            }  
        }  
    }  
    
    int main(){
        int T;scanf("%d",&T);
        getchar();
        while(T--){n=0;
            // 手动初始化 tools 数组
            for (int i = 0; i < 100000; ++i) {
                tools[i] = 0;
            }
            gets(tools);
            cut(tools);
            m=n;
            for(int i=1;i<n;++i){
                for(int j=i+1;j<=n;++j){
                    mp[i][j]=mp[j][i]=++m;
                }
            }
            for(int i=n;i>=1;--i){
                if(build(i)==n*(n-1)/2){
                    printf("%d\n",i );
                    break;
                }
            }
        }
        return 0;
    }
    
    • 1

    信息

    ID
    1699
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者