Codeforces Round 1063 (Div. 2)
https://codeforces.com/contest/2163
B
预处理需要做到求出每个数左边第一个小于自己的数以及左边最后第一个小于自己的数,就可以确定一个范围\([L_l,L_r]\),还需要求出右边第一个大于自己的数以及最后一个大于自己的数,可以确定范围\([R_l,R_r]\)。这个可以在线使用权值线段树来做维护区间最大值和最小值。
之后我们就枚举\(x_i=1\)的位置,以\(i\)为左边界,确定一个最小的范围\([L_{i,r},R_{i,l}]\),以及可以调节的边界\([L_{i,l},R_{i,r}]\),然后我们去将尽可能多的\(x_i=1\)的位置加入这个,直到加入这个\(i\)不能满足最小范围。
不能这样做,因为可能有其他对1进行分组的方法会比这样简单的贪心对。那我们思考一下题解的方法的正确性:
因为最多构造5个区间,所以我们从必要性入手,肯定有\(x_1,x_n,x_{pos_1},x_{pos_n}\)这些位置都不能为1,否则不能构造。
如果这些位置都不为1的情况下,这4个点将整个区间分为了3段,我们一次来看每一段:
不妨假设为1 pos1 posn n
那么对于[1,pos1],那么对于在[1,pos1]的i,分情况讨论:(1)p[i]<p[1]的肯定可以直接满足;(2)对于p[i]>p[1]的,我们可以再加一个区间[1,posn],这样就保证了区间[1,pos1]被完全覆盖。
对于[pos1,posn],所有在[pos1,posn]的i,都有p[pos1]<p[i]<p[posn],显然是可以覆盖的。
对于[posn,n],对于在[posn,n]的i,分情况讨论:(1)p[i]>p[n]的直接满足;(2)对于p[i]<p[n]的,我们可以增加区间[pos1,n],这样就保证了区间[posn,n]被完全覆盖。
上面总共用到区间数量为5个,分别为:
[1,pos1],[1,posn],[pos1,posn],[pos1,n],[posn,n]。
对于1 posn pos1 n也是一样的。
综上,结果为:
[1,pos1],[1,posn],[min(pos1,posn),max(pos1,posn)],[pos1,n],[posn,n]。
所以也就是说,只要必要条件满足,我们总是可以找到一种合法的方案,所以直接写就对了。
void solve() {
int n;
cin >> n;
vector<int> a(n+1);
int pos1=1,posn=1;
for(int i=1;i<=n;i++){
cin >> a[i];
}
string x;
cin >> x;
x=" "+x;
for(int i=1;i<=n;i++){
if(a[i]>a[posn]) posn=i;
if(a[i]<a[pos1]) pos1=i;
}
if(x[1]=='1'||x[n]=='1'||x[pos1]=='1'||x[posn]=='1'){
cout << -1 << endl;
return;
}
cout << 5 << endl;
cout << 1 << " " << pos1 << endl;
cout << 1 << " " << posn << endl;
cout << pos1 << " " << n << endl;
cout << posn << " " << n << endl;
cout << min(pos1,posn) << " " << max(pos1,posn) << endl;
}
C
可以发现总共只有\(n\)条路径,我们把每条路径的\([l,r]\)求出来,加入到\(seg\)中,同时为了方便再加入一个\((0,2\times n+1)\)到\(seg\)中。之后将\(seg\)按照\(l\)从大到小排序,之后用双指针模拟,维护每个\(l\)的最小\(R[l]\)。当然也可以用线段树区间修改取小完成。
void solve() {
int n;
cin >> n;
vector<vector<int>> a(3,vector<int>(n+1));
for(int j=1;j<=2;j++){
for(int i=1;i<=n;i++){
cin >> a[j][i];
}
}
vector<vector<int>> pre(n+1,vector<int>(2)),suf(n+2,vector<int>(2));
pre[0][0]=0,pre[0][1]=2*n+1;
suf[n+1][0]=0,suf[n+1][1]=2*n+1;
for(int i=1;i<=n;i++){
pre[i][0]=max(pre[i-1][0],a[1][i]);
pre[i][1]=min(pre[i-1][1],a[1][i]);
}
for(int i=n;i>=1;i--){
suf[i][0]=max(suf[i+1][0],a[2][i]);
suf[i][1]=min(suf[i+1][1],a[2][i]);
}
vector<pii> seg(n+1);
for(int i=1;i<=n;i++){
int mx=max(suf[i][0],pre[i][0]);
int mn=min(suf[i][1],pre[i][1]);
seg[i]={mn,mx};
}
seg[0]={0,2*n+1};
sort(seg.begin(),seg.end(),[&](pii x,pii y){
if(x.first!=y.first) return x.first>y.first;
else return x.second<y.second;
});
int ans=0;
//按照l从大到小去维护最小R[l]
int mnr=2*n+1;
int i=0,j=2*n;
while(1){
auto [l,r]=seg[i];
if(i+1<=n) i++;
while(j>=l+1){
ans+=2*n-mnr+1;
j--;
}
mnr=min(mnr,r);
if(j==0) break;
}
cout << ans << endl;
}

浙公网安备 33010602011771号