UNR2023

UNR唯数不多的能切掉的两道题目(其中有一题还犯傻被卡常了,中间还过了两发QWQ)

DAY1 T1
题意:两位玩家,小青鱼和空间的使者,将轮流进行操作。在每一轮中,玩家可以从序列中选择任意两个相邻的元素并将它们删除。删除后,这两个元素两侧的剩余序列将会自动合并。这样的操作将持续进行,直到序列中只剩下一个元素。

在这场游戏中,小青鱼是先手。他的目标是在游戏结束时让剩下的那个整数尽可能的大,而智者则希望让最后剩下的整数尽可能小。最后剩下什么?

这题很像吴畅那个神秘题啊,但是判定条件简单一些.首先我们考虑二分一个答案,把大于等于这个数的赋成$2$,小于的赋成$1$.
我们接着考虑最后一步是谁操作(起码我的做法要分情况讨论,大部分神奔不需要)
我们考虑最后是智者,那么我们知道如果最后留给智者的是$212$.那么小青鱼一定可以留下答案.我们考虑判定条件:我们每次是删除两个数,也就是原本$12$数的位置的奇偶不变,我们就知道小青鱼一定要把奇数位置的$1$删除,这样就一定能获胜.
如果最后是小青鱼操作,那么如果智者给小青鱼留下了$121$则一定可以删除答案,所以智者要把奇数位置的$2$删完.然后就做完了.

#include<bits/stdc++.h>
using namespace std;
namespace FastIO {
    char buf[1<<21], *p1=buf, *p2=buf;
    inline int getch (void) {
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read (void) {
        int x = 0, f = 1, ch = getch();
        while(!isdigit(ch)) {
            if(ch == '-') f = -f;
            ch = getch();
        }
        while(isdigit(ch)) {
            x = x * 10 + ch - '0';
            ch = getch();
        }
        return x * f;
    }
    char buf2[1<<21], buf3[25];
    int tp_l, buf2_l=-1;
    inline void flush (void) {
        fwrite (buf2, 1, buf2_l+1, stdout), buf2_l=-1;
    }
    inline void print (int x, char ch=10) {
        if(buf2_l>(1<<20)) flush();
        if(x<0) buf2[++buf2_l]='-', x=-x;
        do buf3[++tp_l]=x%10+48;
        while(x/=10);
        do buf2[++buf2_l]=buf3[tp_l];
        while(--tp_l);
        buf2[++buf2_l] = ch;
    }
}
using FastIO::read;
using FastIO::print;
int a[1000050],b[1000005],ans,flag,num,n,t,mn;
int st[1000050],cnt=0;
bool check1(int x){
    for(int i=1;i<=n;i++){
        if(a[i]>=x)b[i]=2;
        else b[i]=1;
    }
    int ss=0;
    for(int i=1;i<=n;i++){
        if((i%2==1)&&b[i]==1){
            ss++;i++;
        }
    }
    if(ss<=num/2)return 1;
    return 0;
}
bool check2(int x){
    for(int i=1;i<=n;i++){
        if(a[i]>=x)b[i]=2;
        else b[i]=1;
    }
    int ss=0;
    for(int i=1;i<=n;i++){
        if((i%2==1)&&b[i]==2){
            ss++;i++;
        }
    }
    if(ss<=num/2)return 1;
    return 0;
}
int main(){
    // freopen("A.in","r",stdin);
    // freopen("A.out","w",stdout);
    t=read();
    while(t--){
        n=read();mn=n+1;
        for(int i=1;i<=n;i++){
            a[i]=read();
            mn=min(mn,a[i]);
        }
        num=n/2;flag=num%2;
        int l=1,r=n,ans=mn;
        if(flag==0){
            while(l<=r){
                int mid=(l+r)/2;
                if(check1(mid)){
                    ans=mid;
                    l=mid+1;
                }else {
                    r=mid-1;
                }
            }
        }else {
            while(l<=r){
                int mid=(l+r)/2;
                if(check2(mid)){
                    r=mid-1;
                }else {
                    ans=mid;
                    l=mid+1;
                }
            }
        }
        printf("%d\n",ans);
    }
    FastIO::flush();
    return 0;
}
View Code

 

关于DAY1 T2我自己的做法就是每长度为$16$为一块,然后暴力把每种的最优答案跑出来直接拼起来.

但是WT直接把长度小于等于$576$的直接贪心bitset匹配找到最长的,然后过了!很厉害.

 

DAY2 T1
这题赛时竟然想出来了,但是抽象的我被卡常了.
首先有一个包的暴力是$k=1$,这一部分直接从后到前扫描线,每次看当前这个位置最多能存活多久,这个直接二分+RMQ(区间$a$的最大值),然后直接线段树区间覆盖.
对于每个询问[l,r]我们挂在$l$上,然后查询线段树上$r$的位置的值.

对于正解这题有个我们需要自己手玩一下发现一些性质,我们发现一个区间选$k$个数,$b$值前$k-1$大的肯定会选,具体的我们考虑若当前只有前$k-2$大的,那么碰到$k-1$大的时候一定会把其中一个弹出,并前后面总弹出最小的那个$b$.
所以我们先用主席树把这前$k-1$的$c$加起来,接着我们考虑还会有个什么?
首先我们找到$[l,r]$区间中,$b$值前$k$大的数最靠后面的那个位置$pos$.如果从$l$做到$pos$,我们发现那个特殊的数一定是$b$值为第$k$大的,因为在$pos$时一定会把最小的$b$弹出,前面也是一样的.
所以我们可以找出$b$值第$k$大的数,这个可以主席树上二分,至于最远的位置,我赛时脑子一抽,写了个$2log$二分+区间求和(被卡常,但是能过).其实可以扫描线+树状数组单$log$解决.
对于$[pos+1,r]$其实做法就是$k=1$的情况,只不过扫描线到$l$的时候还需要判断一下那个$b$值第$k$大的数的存活情况(直接二分就行)

于是就做完了,我太乐了,DAY2会题却比DAY1考的垃圾,果然还是要打暴力.

提供单$log$不卡常代码:

#include<bits/stdc++.h>
using namespace std;
namespace FastIO {
    char buf[1<<21], *p1=buf, *p2=buf;
    inline int getch (void) {
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read (void) {
        int x = 0, f = 1, ch = getch();
        while(!isdigit(ch)) {
            if(ch == '-') f = -f;
            ch = getch();
        }
        while(isdigit(ch)) {
            x = x * 10 + ch - '0';
            ch = getch();
        }
        return x * f;
    }
    char buf2[1<<21], buf3[25];
    int tp_l, buf2_l=-1;
    inline void flush (void) {
        fwrite (buf2, 1, buf2_l+1, stdout), buf2_l=-1;
    }
    inline void print (int x, char ch=10) {
        if(buf2_l>(1<<20)) flush();
        if(x<0) buf2[++buf2_l]='-', x=-x;
        do buf3[++tp_l]=x%10+48;
        while(x/=10);
        do buf2[++buf2_l]=buf3[tp_l];
        while(--tp_l);
        buf2[++buf2_l] = ch;
    }
}
using FastIO::read;
using FastIO::print;
int n,qq;
struct stu{
    int a,b,c;
}s[500005];
struct node{
    int l,r,k,id,val;
}q[500005];
long long ans[500005];
int root[500005],pos[500005];
vector<int>g[500005],p[500005];
struct tree{
    int lc,rc,num,mx;
    long long sum;
}t[12000000];
int tot,po,ls;
void xg(int &k,int k1,int l,int r,int pos,int v1,int v2){
    k=++tot;
    t[k]=t[k1];
    t[k].num+=v1;
    t[k].sum+=v2;
    if(l==r&&l==pos)return;
    int mid=(l+r)>>1;
    if(pos<=mid)xg(t[k].lc,t[k1].lc,l,mid,pos,v1,v2);
    else xg(t[k].rc,t[k1].rc,mid+1,r,pos,v1,v2);
}
long long query(int k1,int k2,int l,int r,int k){
    if(l==r){ls=pos[l];return t[k2].sum-t[k1].sum;}
    int gs=t[t[k2].rc].num-t[t[k1].rc].num;
    int mid=(l+r)>>1;
    if(gs>=k){
        return query(t[k1].rc,t[k2].rc,mid+1,r,k);
    }else {
        return t[t[k2].rc].sum-t[t[k1].rc].sum+query(t[k1].lc,t[k2].lc,l,mid,k-gs);
    }
}
int query1(int k1,int k2,int l,int r,int L){
    if(l>=L)return t[k2].num-t[k1].num;
    int mid=(l+r)/2;
    if(L<=mid)return query1(t[k1].rc,t[k2].rc,mid+1,r,L)+query1(t[k1].lc,t[k2].lc,l,mid,L);
    return query1(t[k1].rc,t[k2].rc,mid+1,r,L);
}
struct szsz{
    int c[500005];
    int lowbit(int x){
        return x&(-x);
    }
    void xg(int i,int val){
        for(;i;i-=lowbit(i))c[i]=max(c[i],val);
    }
    int query(int i){
        int res=0;
        for(;i<=n;i+=lowbit(i))res=max(res,c[i]);
        return res;
    }
}t1;

namespace RMQ{
    int logg[500005],mx[21][500005];
    void ycl(){
        logg[0]=(-1);
        for(int i=1;i<=n;i++){
            logg[i]=logg[i>>1]+1;
            mx[0][i]=s[i].a;
        }
        for(int j=1;j<=logg[n];j++){
            for(int i=1;i+(1<<j)-1<=n;i++){
                mx[j][i]=max(mx[j-1][i],mx[j-1][i+(1<<(j-1))]);
            }
        }
        return;
    }
    int query(int l,int r){
        if(l>r)return 0;
        int c=logg[r-l+1];
        return max(mx[c][l],mx[c][r-(1<<c)+1]);
    }
}

struct segment{
    int mn[500005*4];
    void pushdown(int k){
        if(mn[k]){
            mn[k<<1]=mn[k];mn[k<<1|1]=mn[k];mn[k]=0;
        }
    }
    void xg(int k,int l,int r,int L,int R,int id){
        if(l>=L&&r<=R){
            mn[k]=id;
            return;
        }
        int mid=(l+r)/2;
        pushdown(k);
        if(L<=mid)xg(k<<1,l,mid,L,R,id);
        if(R>mid)xg(k<<1|1,mid+1,r,L,R,id);
    }
    int query(int k,int l,int r,int pos){
        if(l==r&&l==pos)return mn[k];
        int mid=(l+r)>>1;
        pushdown(k);
        if(pos<=mid)return query(k<<1,l,mid,pos);
        else return query(k<<1|1,mid+1,r,pos);
    }
}t2;

int main(){
    // freopen("A.in","r",stdin);
    // freopen("A.out","w",stdout);
    n=read();qq=read();
    for(int i=1;i<=n;i++){
        s[i].a=read();
    }
    for(int i=1;i<=n;i++){
        s[i].b=read();
        pos[s[i].b]=i;
    }
    for(int i=1;i<=n;i++){
        s[i].c=read();
    }
    for(int i=1;i<=n;i++){
        xg(root[i],root[i-1],1,n,s[i].b,1,s[i].c);
    }
    for(int i=1;i<=qq;i++){
        q[i].l=read();q[i].r=read();q[i].k=read();
        q[i].id=i;
        po=q[i].l-1;
        if(q[i].k-1>=1){
            ans[i]=query(root[q[i].l-1],root[q[i].r],1,n,q[i].k-1);
            query(root[q[i].l-1],root[q[i].r],1,n,q[i].k);
            q[i].r=q[i].r;q[i].val=ls;
            p[q[i].r].push_back(i);
        }else {
            q[i].l=po+1;q[i].val=0;
        }
    }
    for(int i=1;i<=n;i++){
        t1.xg(s[i].b,i);
        for(int j=0;j<p[i].size();j++){
            int id=p[i][j];
            q[id].l=t1.query(s[q[id].val].b)+1;
        }
    }

    for(int i=1;i<=qq;i++){
        if(q[i].l>q[i].r){
            ans[i]+=s[q[i].val].c;
            continue;
        }
        g[q[i].l].push_back(i);
    }
    RMQ::ycl();
    for(int i=n;i>=1;i--){
        int l=i,r=n,ss=i;
        while(l<=r){
            int mid=(l+r)>>1;
            if(s[i].b>RMQ::query(i+1,mid)){
                ss=mid;l=mid+1;
            }else r=mid-1;
        }
        t2.xg(1,1,n,i,ss,i);
        for(int j=0;j<g[i].size();j++){
            int id=g[i][j];
            int val=q[id].val;
            if(val==0){
                int num=t2.query(1,1,n,q[id].r);
                ans[id]=ans[id]+s[num].c;
                continue;
            }
            l=i,r=n,ss=i-1;
            while(l<=r){
                int mid=(l+r)>>1;
                if(s[val].b>RMQ::query(i,mid)){
                    ss=mid;l=mid+1;
                }else r=mid-1;
            }
            if(ss>=q[id].r){
                ans[id]=ans[id]+s[val].c;
            }else {
                int num=t2.query(1,1,n,q[id].r);
                ans[id]=ans[id]+s[num].c;
            }
        }
    }
    for(int i=1;i<=qq;i++){
        printf("%lld\n",ans[i]);
    }
    FastIO::flush();
    return 0;
}
View Code

 

posted @ 2023-07-16 19:33  星棋居  阅读(35)  评论(0)    收藏  举报