专栏文章

CF1918

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minyo8it
此快照首次捕获于
2025/12/02 10:30
3 个月前
此快照最后确认于
2025/12/02 10:30
3 个月前
查看原文

CF1918

D

Solution

最大值最小,首先显然有二分答案。
观察阻断了一个点,能取到的上一个阻断的点显然是一个区间,进一步发现,其形如一个滑动窗口。
定义 fif_i 为阻断了第 ii 个点,前 ii 个点被阻断权值和最小值。
fi=minj<i,siisjx(fj+ai)f_i = \min_{j<i,s_{i-i}-s_j \le x}(f_j+a_i)
其中 sis_iaa 的前缀和,xx 为当前二分的答案。
使用单调队列解决,时间复杂度 O(nlognV)O(n \log nV)

Code

CPP
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int T,n,a[N],sum[N],f[N];
int q[N];
int read(){
    int k=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
        ch=getchar();
    while(ch>='0'&&ch<='9')
        k=k*10+ch-'0',ch=getchar();
    return k;
}
bool check(int x){
    int l=1,r=0;
    for(int i=1;i<=n+1;i++){
        q[++r]=i-1;
        while(l<r&&f[q[r]]<=f[q[r-1]])
            q[r-1]=q[r],r--;
        while(l<=r&&sum[i-1]-sum[q[l]]>x)
            l++;
        f[i]=f[q[l]]+a[i];
    }
    return f[n+1]<=x;
}
signed main(){
    T=read();
    while(T--){
        n=read();
        for(int i=1;i<=n;i++)
            a[i]=read(),sum[i]=a[i]+sum[i-1];
        a[n+1]=0;
        int l=1,r=1e18;
        while(l<r){
            int mid=(l+r)>>1;
            if(check(mid))
                r=mid;
            else
                l=mid+1;
        }
        printf("%lld\n",l);
    }
    return 0;
}

E

Solution

由于 xx 未知,首先可以花费 O(n)O(n) 次询问求出最大值位置 mxmx,最小值位置 mimi
这样我们就可以控制 xx,询问 mxx+1mx \to x+1,询问 mix1mi \to x-1
如果移动 xx 无代价,那么对每个 ii 单独二分求解即可,但移动 xx 要花费代价,那么使用整体二分,即可解决本题。

Code

CPP
#include <bits/stdc++.h>
using namespace std;
const int N=2005;
int T,n,mi,mx,now,p[N],p1[N],p2[N],ans[N];
int ask(int x){
    cout<<"? "<<x<<endl;
    cout.flush();
    char c;
    cin>>c;
    if(c=='<'){
        now--;
        return -1;
    }
    else if(c=='=')
        return 0;
    else{
        now++;
        return 1;
    }
}
void change(int x){
    while(now<x) ask(mx);
    while(now>x) ask(mi);
}
void solve(int l,int r,int L,int R){
    if(l>r) return;
    if(l==r) ans[p[l]]=L;
    int mid=(L+R)>>1,cnt1=0,cnt2=0;
    change(mid);
    for(int i=l;i<=r;i++){
        int t=ask(p[i]);
        if(t==-1)
            p1[++cnt1]=p[i],ask(mx);
        else if(t==0)
            ans[p[i]]=mid;
        else
            p2[++cnt2]=p[i],ask(mi);
    }
    for(int i=l;i<=l+cnt1-1;i++)
        p[i]=p1[i-l+1];
    for(int i=l+cnt1+1;i<=r;i++)
        p[i]=p2[i-l-cnt1];
    solve(l,l+cnt1-1,L,mid-1);
    solve(l+cnt1+1,r,mid+1,R);
}
int main(){
    cin>>T;
    while(T--){
        mx=0,mi=0;
        cin>>n;
        int t;
        for(int i=1;i<=n;i++){
            t=ask(i);
            if(t==-1){
                if(mx!=0) ask(mx);
                continue;
            }
            else{
                mx=i;
                while(t!=0)
                    t=ask(i);
            }
        }
        for(int i=1;i<=n;i++){
            t=ask(i);
            if(t==1){
                if(mi!=0) ask(mi);
                continue;
            }
            else{
                mi=i;
                while(t!=0)
                    t=ask(i);
            }
        }
        t=ask(mi);
        while(t!=0)
            t=ask(mi);
        now=1;
        for(int i=1;i<=n;i++)
            p[i]=i;
        solve(1,n,1,n);
        cout<<"!";
        for(int i=1;i<=n;i++)
            cout<<" "<<ans[i];
        cout<<endl;
        cout.flush();
    }
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...