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个询问,从某点出发最远到达哪个点。
image
思路:开始想的建树合并,但是复杂度太高。。实际上,从\(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

还没补,晚点再写

posted @ 2023-08-15 00:54  holy_crap  阅读(47)  评论(0编辑  收藏  举报