专栏文章
CF1918
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minyo8it
- 此快照首次捕获于
- 2025/12/02 10:30 3 个月前
- 此快照最后确认于
- 2025/12/02 10:30 3 个月前
CF1918
D
Solution
最大值最小,首先显然有二分答案。
观察阻断了一个点,能取到的上一个阻断的点显然是一个区间,进一步发现,其形如一个滑动窗口。
定义 为阻断了第 个点,前 个点被阻断权值和最小值。
其中 为 的前缀和, 为当前二分的答案。
使用单调队列解决,时间复杂度 。
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
由于 未知,首先可以花费 次询问求出最大值位置 ,最小值位置 。
这样我们就可以控制 ,询问 ,询问 。
如果移动 无代价,那么对每个 单独二分求解即可,但移动 要花费代价,那么使用整体二分,即可解决本题。
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 条评论,欢迎与作者交流。
正在加载评论...