首页 > 其他分享 >决斗 题解

决斗 题解

时间:2024-01-22 09:11:07浏览次数:25  
标签:rt int 题解 update 决斗 mid tr 青蛙

决斗 题解

赛题来自 OIFHA 第四场模拟赛。

原题展现

青蛙哥与名侦探柯南正在进行一场对决。

他们两个人每人有 \(n\) 张牌,每张牌有一个点数。

并且在接下来的 \(n\) 个回合中每回合青蛙哥与名侦探柯南两人会各自打出一张牌。

每回合裁判会检查,打出的牌点数更高的一方获胜从而得到一分,如果二人点数相同,则不得分。

然而现在青蛙哥通过偷看的方法得到了名侦探柯南的出牌顺序,他可以任意定一个自己的出牌的顺序。

他首先希望让自己的得分尽可能高,然后就是希望在让自己的得分尽可能高这个前提下,最大化自己从第一回合开始到最后一个回合结束过程中,每回合出牌点数构成的字符串的字典序。

数据范围:\(n,a_i\leq 10^5\)。

Solution

首先假设我们已经得知青蛙最高得分是多少。

对于第 \(i\) 回合,考虑让不让青蛙在这个回合赢。

如果赢的话,可以取最大的 \(b_j\),也可以取只比 \(a_i\) 大一点的 \(b_j\)。

如果不让他赢,可以取最小的 \(b_j\),也可以取只比 \(a_i\) 小一点的 \(b_j\)。

可见,让青蛙在这个回合赢或输,可取的值都是一个 \([l,r]\) 区间。题目要求字典序最大,而我们也不能直接确定青蛙在这个区间取多少时字典序最大。所以这里需要二分答案。

至于一开始的假设:“已经得知最高得分”,这个怎么实现呢?

可以考虑维护一棵权值线段树,每个节点都是一个三元组 \((s,s_1,s_2)\)。分别表示:青蛙哥的得分,柯南的牌数,青蛙的牌数。

在合并区间的时候,肯定是拿青蛙点数大的牌去对抗柯南点数小的牌。得分就是 tr[rt].s=tr[lson].s+tr[rson].s+k,其中 k=min(tr[lson].s1,tr[rson].s2)

时间复杂度 \(O(n\log^2 V)\),\(V\) 是值域。

code

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define ls rt<<1
#define rs ls|1

const int MAXN=1e5+5,m=1e5;

int n;
int a[MAXN],b[MAXN];
struct tree
{
    int s,s1,s2;
}tr[MAXN<<2];
multiset<int> s;

void pushup(int rt)
{
    int minz=min(tr[ls].s1,tr[rs].s2);
    tr[rt].s=tr[ls].s+tr[rs].s+minz;
    tr[rt].s1=tr[ls].s1+tr[rs].s1-minz;
    tr[rt].s2=tr[ls].s2+tr[rs].s2-minz;
}

void update(int rt,int l,int r,int x,int v1,int v2)
{
    if(l==r)
    {
        tr[rt].s1+=v1;
        tr[rt].s2+=v2;
        return;
    }
    int mid=l+r>>1;
    if(x<=mid) update(ls,l,mid,x,v1,v2);
    else update(rs,mid+1,r,x,v1,v2);
    pushup(rt);
}

signed main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++) scanf("%lld",&b[i]),s.insert(b[i]);

    for(int i=1;i<=n;i++)
        update(1,1,m,a[i],1,0),update(1,1,m,b[i],0,1);

    int cnt=tr[1].s;
    for(int i=1;i<=n;i++)
    {
        update(1,1,m,a[i],-1,0);
        int l=a[i]+1,r=*s.rbegin(),mid,ans;
        while (l<=r)
        {
            mid=l+r>>1;
            update(1,1,m,mid,0,-1);
            if(tr[1].s+1==cnt) l=mid+1,ans=mid;
            else r=mid-1;
            update(1,1,m,mid,0,1);
        }
        update(1,1,m,ans,0,-1);
        if(a[i]<*s.rbegin()&&tr[1].s+1==cnt)
        {
            --cnt;
            printf("%lld ",ans);
            s.erase(s.find(ans));
        }
        else
        {
            update(1,1,m,ans,0,1);
            l=1,r=a[i],ans=l;
            while (l<=r)
            {
                mid=l+r>>1;
                update(1,1,m,mid,0,-1);
                if(tr[1].s==cnt) l=mid+1,ans=mid;
                else r=mid-1;
                update(1,1,m,mid,0,1);
            }
            update(1,1,m,ans,0,-1);
            printf("%lld ",ans);
            s.erase(s.find(ans));
        }
    }

    return 0;
}

标签:rt,int,题解,update,决斗,mid,tr,青蛙
From: https://www.cnblogs.com/wang-holmes/p/17979268

相关文章

  • UVA10295 Hay Points 题解
    题目大意:给你\(n\)个单词,每一个单词的值为\(v_i\),让你求出在一个文章段落里的出现过的单词的值之和。思路:可以用STL库中的map来存储一个单词的值,最后在处理的时候可以直接累加。附上你们最期待的代码:#include<bits/stdc++.h>usingnamespacestd;map<string,int......
  • AT_arc169_a的题解
    关于我在赛场上一题都没有切,后面自己推出来正解这件事~题面翻译给定一个长度为\(N\)的整数序列\(A=(A_1,A_2,\cdots,A_N)\)和另一个长度为\(N-1\)的整数序列\(P=(P_2,\cdots,P_N)\)。注意\(P\)的索引从\(2\)开始。对于每个\(i\),保证\(1\leqP_i<i\)。现在您......
  • UVA11218的题解
    题目翻译大意有九个人要去KTV唱歌,每三个人为一组分成三组,现在给出了\(n\)种分的组合,输入四个数\(a,b,c,s\)分别代表\(a,b,c\)这三个人的构成一个组合能获得\(s\)分,现在要求最多能获得多少得分。如果无法把分配九个人就输出-1。分析数据范围:看这数据,\(n<81\)不......
  • 2024.1.21模拟赛 C题解
    简要题意略思路首先有一个\(O(nk)\)的暴力dp,30pts我们可以发扬人类智慧,构造势能函数\(U_x=\sum_{未选择的点i}dis(i,x)+h_i\),当前在\(x\)点定义\(f_i\)表示走到\(i\)点时势能函数的最小值,\(s_i\)表示\(i\)到起点的距离容易发现只会跨过起点进行转移,于是\(f_i=f_j+2\tim......
  • 「闲话随笔」【数据删除】考试题解
    「闲话随笔」【数据删除】考试题解点击查看目录目录「闲话随笔」【数据删除】考试题解T2T3T4T5T6T7T1T8T9被教练斩了.级部为啥不让公布分数?哦好像确实不该.咋四机房就我还没停whk,那我还挺高贵的.昨天中午saidtoFLORIZ:感觉现在是提前体验退役生活了,回班之后小测......
  • 2024.1.21模拟赛 B题解
    题目大意略思路首先有一个50pts的网络流暴力考虑按照\(dp\)值分层,发现在同一层内,随着\(i\)递增,\(a_i\)递减由此可以进一步推出每一个点连接的出边,是下一层的一个区间,并且区间是单调的于是可以线段树优化建边,拿到60pts接着考虑模拟网络流,发现如果每次都选择第一条出边的话,就......
  • 初三选拔模拟赛题解
    目录T2T3T4T5T6T7给个正常的题解以正视听.不过说好的普及难度呢?如果有问题请指出.T2注意到答案一定可以取到最小区间的长度\(len\),一种方案是按\(0\dotslen-1\)循环填.T3大致有两种做法:维护每个手指的次数\(c_i\)和占用的键数\(t_i\),按\(\frac{c_i}{t_i+1}\)......
  • 1.21闲话暨模拟赛题解
    未卜先知推歌:二重变革/洛天依,言和byDELA上午写了模拟赛,下午不给我发代码不让我改题不让我看题面,smjb模拟赛一共9道题,4道原题(2道原题,2道"原"题),抛去3道不写的一共6道题T1「尘世闲游」(原神题)没让写T2「一心净土」(原神题&&原题「CF740C」)题解我这里一共找到......
  • CF1375B Neighbor Grid 题解
    题意简述给你一个$n$行$m$列的矩阵,要求你让这个矩阵是“完美”的。“完美”的定义如下:若当前的格子里是一个正整数$k$,那么与这个网格相邻(有公共边)的$k$个格子也必须有一个正整数。若当前的格子里是$0$,那么不受上述的限制。你可以对任意的一个格子加上$1$,次数......
  • P5362 [SDOI2019] 连续子序列 题解--zhengjun
    题面传送门提供一种和其他题解完全不同的解法。记\(P_0\)为题中给出的序列,\(P_1\)为\(P_0\)取反的结果。记\(S_{l\simr}\)表示\(S_lS_{l+1}\dotsS_{r}\)。方便起见,\(P\)下标从\(0\)开始,其余的串都是从\(1\)开始。这里用\(P_{0,i}=\operatorname{popcount(i)}......