2023/8/14题解
1. Codeforces Round 892 (Div. 2), problem: (D) Andrey and Escape from Capygrad
题目传送门
题意:在X轴上有n个传送门装置,每个传送门对应四个参数\(l\leq a\leq b\leq r\),可以在\([l,r]\)上任意一点传送到\([a,b]\)上任意一点。
有Q个询问,从某点出发最远到达哪个点。
思路:开始想的建树合并,但是复杂度太高。。实际上,从\(x_i\)点出发,最远走到的位置一定\(\geq x_i\) , 同时,\(b_i \leq r_i\)代表向左走对答案没有任何贡献,所以,策略是只向右移动。只要维护\([l_i,b_i]\)所构成的线段合并即可,即上图 左黑端点 右红端点 的线段。
赛时最后一分钟想到但是没时间码了,可恶!
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<PII, int> PPI;
#define io ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define FOR(i,s,e)for(int i=(s);i<=(e);i++)
#define mem(a, b) memset((a), (b), sizeof(a))
#define inf 0x3f3f3f3f
#define seed 13331
#define MOD1 1000000007
#define MOD2 1000000009
#define MOD3 998244353
const int N = 2e5+7;
long long read(){
char ch=getchar();long long nn=0,ssss=1;
while(ch<'0'||ch>'9'){if(ch=='-')ssss*=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){nn=nn*10+(ch-'0');ch=getchar();}
return nn*ssss;
}
void solve(int i_)
{
int n;
cin>>n;
vector<array<int,2>> v,v2;
for(int i=1;i<=n;i++)
{
int a,b,c,d;
cin>>a>>b>>c>>d;
v2.push_back({a,d});
}
sort(v2.begin(),v2.end());
for(auto &[l,r]:v2)
{
if(!v.empty() && v.back()[1]>=l)
v.back()[1] = max(v.back()[1],r);
else
v.push_back({l,r});
}
cin>>n;
for(int i=1;i<=n;i++)
{
int p;
cin>>p;
int j = lower_bound(v.begin(),v.end(),array{p+1,0})-1-v.begin();
//p+1位置所在的线段无法到达,所求线段为左端点大于等于p+1的线段的上一条线段
if(j>=0)
p = max(p,v[j][1]);
cout<<p<<" ";
}
cout<<"\n";
}
int main()
{
io;
int T=1,i_;
cin>>T;
for(i_=1;i_<=T;i_++)
solve(i_);
return 0;
}
2.Non-Puzzle: Error Permutation - 2023牛客暑期多校训练营9-D
题解:对于某个左端点\(l\)和\(a_i\),令其不合法的右端点为几个区间,那么答案就是每个左端点\(l\)对应的合法右端点\(r\)区间内元素个数。具体看代码注释
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<PII, int> PPI;
#define io ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define FOR(i,s,e)for(int i=(s);i<=(e);i++)
#define mem(a, b) memset((a), (b), sizeof(a))
#define inf 0x3f3f3f3f
#define PI acos(-1)
#define seed 13331
#define MOD1 1000000007
#define MOD2 1000000009
#define MOD3 998244353
#define fr first
#define se second
const int N = 1e6+7;
void solve(int i_)
{
int n;
cin>>n;
vector<int> v(n+1);
vector<vector<int>> res(n+1,vector<int>(n+2));
//差分数组记得多开1个空间,防止越界
for(int i=1;i<=n;i++) cin>>v[i];
for(int i=1;i<=n;i++)
{
int r = i,l=i;
while(r<n&&v[r+1]>v[i]) r++;
//v[r+1]>v[i]导致v[i]排名从第1小变成第2小,所以第i位在[l,r+1]区间上合法,[l,r]为不合法区间
res[i][l] ++;
res[i][r+1] --;
for(int j=i-1;j>=1;j--)
{
if(v[j]>v[i])
//出现比v[i]大的元素,导致v[i]第k小的排名没有上升,但是下标+1,此时需要右侧区间不合法
{
r++;
l=r;
while(r<n&&v[r+1]>v[i]) r++;
//对于左端点为j,找到下一个比v[i]小的数字,更新v[i]的不合法区间
}
if(r<=n)
{
res[j][l] ++;
res[j][r+1] --;
//对所有v[i]左侧的点j记录以v[j]为左端点的v[i]的不合法区间
}
}
}
int ans = 0;
for(int i=1;i<=n;i++)
{
int t = 0;
for(int j=i;j<=n;j++)
(t += res[i][j]) == 0 && ans++;
//如果对于左端点i,j未被任何不合法区间标记,那么[i,j]是一个正确答案
}
cout<<ans<<"\n";
}
int main()
{
io;
int T=1,i_;
cin>>T;
for(i_=1;i_<=T;i_++)
solve(i_);
return 0;
}
3.Non-Puzzle: Segment Pair - 2023牛客暑期多校训练营9-I
还没补,晚点再写