csp-s模擬測試103「game,time」

time

題解

貪心考慮,考試時想錯了,我想的是移動最大值,枚舉最大值位置,而後把左面和右面逆序對拼起來,node

固然,處理不了有多個最大值狀況,因而我就想着打個部分分吧c++

然而對拍仍是掛,ide

枚舉最大值位置是不對的函數

考慮一種狀況a,b,c,d,e,f,gui

其中d最大可能出現a移動到d右面更優,b,c留在左面,我只移動最大值的話默認a,b,c都在左面spa

附贈一組點4 5 2 3 1 6 7 最優決策是6步,方案是2 4 5 6 7 3 1 .3d

出現了我說的這種狀況code

考試時打這個題花費時間仍是過於多了blog

正解是貪心移動最小值,這樣是保證正確的,只移動最大值至關與限制了一些狀況出現get

而後最小值考慮了全部狀況且必定正確

正難則反__by yangguangjie

代碼

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 111111
ll p[A],a[A],b[A],c1[A],c2[A];
ll n,ans=0;
vector <ll> v[A];
//
void add1(ll x,ll d){for(ll i=x;i!=0&&i<=100000;i+=i&-i) c1[i]+=d;}
ll ask1(ll x,ll ans=0){for(ll i=x;i>=1;i-=i&-i) ans+=c1[i];return ans;}
//
void add2(ll x,ll d){for(ll i=x;i>=1;i-=i&-i) c2[i]+=d;}
ll ask2(ll x,ll ans=0){for(ll i=x;i!=0&&i<=100000;i+=i&-i) ans+=c2[i];return ans;}
void sol(){
    for(ll i=1;i<=n;i++){
        add1(i,1);add2(i,1);
        v[a[i]].push_back(i);
    }
    for(ll i=1;i<=100000;i++){
        if(v[i].size()){
            for(ll fr=0,ba=v[i].size()-1;fr<=ba;){
                ll x=v[i][fr],y=v[i][ba];
                ll l=ask1(x-1),r=ask2(y+1);
//                printf("l=%lld r=%lld\n",l,r);
                if(l<r){
                    ans+=l;
                    add1(x,-1);
                    add2(x,-1);
                    fr++;
                }
                else {
                    ans+=r;
                    add1(y,-1);
                    add2(y,-1);
                    ba--;
                }
            }
        }
    }
}
int main(){
    freopen("time.in","r",stdin);
    freopen("time.out","w",stdout);
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&a[i]),p[i]=i;
    sol();
    printf("%lld\n",ans);
}
View Code

game

題解

作過一個相似的題(老司機的狂歡),也是求字典序最小,也是第一問特別簡單,而後根據第一問推第二問

但實在沒想到能夠每一位上二分求字典序最小

推單調性

若是upper_bound有值具備單調性,當前選的值越大,之後高的可能性就越小

若是upper_bound沒值具備單調性,當前選的值越大,之後得分高的可能越小

可是函數是分段的

能夠分兩次二分

這樣每次set暴力check複雜度$n^2*{log}^2$

如今思考如何check

能夠用權值線段樹維護

維護A的沒用上的牌

維護B的沒用上的牌

向上合併時右子樹每一張A均可以於左子樹中B匹配

代碼大體是這樣

void up(ll x){
    ll de=min(tr[x<<1|1].L,tr[x<<1].R);
    tr[x].s=tr[x<<1].s+tr[x<<1|1].s+de;
    tr[x].L=tr[x<<1].L+tr[x<<1|1].L-de;
    tr[x].R=tr[x<<1].R+tr[x<<1|1].R-de;
}

代碼

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define A 1010100
#define maxx 100000
ll read(){ll x;scanf("%d",&x);return x;}
ll tot,n;
ll b[A],a[A];
multiset<ll> st;
multiset<ll> ::iterator it;
struct node{
    ll l,r,L,R,s;
//L:A的牌
//R:B的牌
//s得分
}tr[A];
void built(ll x,ll l,ll r){
    tr[x].l=l,tr[x].r=r;
    if(l==r){
        return ;
    }
    ll mid=(l+r)>>1;
    built(x<<1,l,mid);
    built(x<<1|1,mid+1,r);
}
void up(ll x){
    ll de=min(tr[x<<1|1].L,tr[x<<1].R);
    tr[x].s=tr[x<<1].s+tr[x<<1|1].s+de;
    tr[x].L=tr[x<<1].L+tr[x<<1|1].L-de;
    tr[x].R=tr[x<<1].R+tr[x<<1|1].R-de;
}
void insert(ll x,ll pla,ll vala,ll valb){
    if(tr[x].l==tr[x].r){
        tr[x].L+=vala;
        tr[x].R+=valb;
        return ;
    }
    ll mid=(tr[x].l+tr[x].r)>>1;
    if(mid>=pla) insert(x<<1,pla,vala,valb);
    else insert(x<<1|1,pla,vala,valb);
    up(x);
}
void getans(ll now){
    insert(1,b[now],0,-1);
    ll l=b[now]+1,r=*st.rbegin(),ans=0;
    while(l<=r){
        ll mid=(l+r)>>1;
        insert(1,mid,-1,0);
        if(tr[1].s+1==tot){
            l=mid+1;
            ans=mid;
        }
        else r=mid-1;
        insert(1,mid,1,0);
    }
    insert(1,ans,-1,0);
    if(tr[1].s+1==tot){
        tot--;
        printf("%d ",ans);
        it=st.find(ans);
        st.erase(it);
        return ;
    }
    insert(1,ans,1,0);
    l=1,r=b[now],ans=0;
    while(l<=r){
        ll mid=(l+r)>>1;
        insert(1,mid,-1,0);
        if(tr[1].s==tot){
            l=mid+1;
            ans=mid;
        }
        else r=mid-1;
        insert(1,mid,1,0);
    }
    insert(1,ans,-1,0);
    printf("%d ",ans);
    it=st.find(ans);
    st.erase(it);
}
int main(){
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    n=read();
    built(1,1,maxx);
    for(ll i=1;i<=n;i++){
        b[i]=read();
        insert(1,b[i],0,1);
    }
    for(ll i=1;i<=n;i++){
        a[i]=read();
        insert(1,a[i],1,0);
        st.insert(a[i]);
    }
    tot=tr[1].s;
    for(ll i=1;i<=n;i++){
        getans(i);
    }
}
View Code
相關文章
相關標籤/搜索