AtCoder Beginner Contest 434 C-E 题解

C. Flapping Takahashi

题意

初始高度为 H H H,可以上下移动,要求每秒高度变化不超过 1 1 1,且高度不能为负。给定 n n n 个限制,第 i i i 个限制为在第 t i t_i ti 秒,高度必须在 [ l i , u i ] [l_i,u_i] [li,ui] 之间。问是否存在一种可行方案。

思路

对于每个限制,若上次的高度区间已经固定,就可以确定这次能否到达。若上次的时间为 p r v prv prv,区间为 [ l , r ] [l,r] [l,r],则这次区间为 [ l − ( t i − p r v ) , r + ( t i − p r v ) ] [l-(t_i-prv),r+(t_i-prv)] [l−(ti−prv),r+(ti−prv)],判断该区间与 [ l i , u i ] [l_i,u_i] [li,ui] 是否有交集,并更新 [ l , r ] [l,r] [l,r],使 l ← max ⁡ ( l , l i ) l\gets \max(l,l_i) l←max(l,li), r ← min ⁡ ( r , u i ) r\gets \min(r,u_i) r←min(r,ui) 即可。

现在只要知道初始的高度区间即可,显然为 [ H , H ] [H,H] [H,H],即 l = r = H l=r=H l=r=H。

时间复杂度 O ( n ) \mathcal{O}(n) O(n)。

C++ 代码

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
void solve(){
    int n,h; cin>>n>>h;
    int L=h,R=h,prv=0;
    bool fl=1;
    for(int i=1;i<=n;i++){
        int t,l,r; cin>>t>>l>>r;
        L-=(t-prv);
        R+=(t-prv);
        fl&=((R>=l&&r>=L));
        L=max(L,l);
        R=min(R,r);
        prv=t;
    }
    if(fl) cout<<"Yes\n";
    else cout<<"No\n";
}
main(){int T;cin>>T;while(T--)solve();}

D. Clouds

题意

有一个 2000 × 2000 2000\times 2000 2000×2000 的平面,有 n n n 个矩形,对于所有 1 ≤ i ≤ n 1\le i\le n 1≤i≤n,求:不被【除矩形 i i i 以外的任何矩形】覆盖的点有多少个。

思路

这题应该可以扫描线做,但是大可不必。

首先计算不去除任何矩形不覆盖的点的个数 a n s ans ans。然后考虑去除矩形 i i i 的贡献。我们发现,去除矩形 i i i 会增加不覆盖的点个数,当且仅当这个点仅被这一个矩形覆盖。所以我们可以对矩形覆盖位置做一个二维差分,记录那些位置只被覆盖一次,然后覆盖这个位置的矩形的贡献就加一。最后对于每个矩形的贡献 r e s i res_i resi,答案即为 a n s + r e s i ans+res_i ans+resi。

C++ 代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=2005;
int a[N][N],cnt[N][N],cf[N][N],res[200005];
main(){
    int n; cin>>n;
    for(int i=1;i<=n;i++){
        int u,d,l,r; cin>>u>>d>>l>>r;
        cnt[u][l]++; cnt[u][r+1]--; cnt[d+1][r+1]++; cnt[d+1][l]--;
        cf[u][l]+=i; cf[u][r+1]-=i; cf[d+1][r+1]+=i; cf[d+1][l]-=i; //差分记录覆盖它的id,若仅被覆盖一次,此值必为覆盖它的矩形编号
    }
    int ans=0;
    for(int i=1;i<=2000;i++){
        for(int j=1;j<=2000;j++){
            cnt[i][j]+=cnt[i-1][j]+cnt[i][j-1]-cnt[i-1][j-1];
            cf[i][j]+=cf[i-1][j]+cf[i][j-1]-cf[i-1][j-1];
            ans+=(cnt[i][j]==0);
            if(cnt[i][j]==1) res[cf[i][j]]++;
        }
    }
    for(int i=1;i<=n;i++) cout<<ans+res[i]<<endl;
    return 0;
}

E. Distribute Bunnies

题意

数轴上有 n n n 只兔子,第 i i i 只兔子要么站在 X i + R i X_i+R_i Xi+Ri,要么站在 X i − R i X_i-R_i Xi−Ri。问 n n n 只兔子位置的集合去重后的大小最大为多少?

思路

建图。把 X i − R i X_i-R_i Xi−Ri 和 X i + R i X_i+R_i Xi+Ri 连边(注意要把点离散化),问题转化为对于每条边,把其中一个端点涂黑,最多能涂黑多少个点。

考虑每个连通块,若大小为 s z sz sz。

  • 若该连通块为一棵树,显然可以任意一点为根,每条边都涂黑深度较大的那个点,最终只剩下根节点,所以可以涂黑 s z − 1 sz-1 sz−1 个点。
  • 若该连通块为一棵基环树,可以以环为根,每条边都涂黑深度较大的那个点,最终只剩下环上的点,显然环上的点可以都涂黑。所以可以涂黑 s z sz sz 个点。
  • 若该连通块为一个无特殊性质的连通图,可以找到任意一棵生成树,再加一条边变为基环树,转化为上述情形,可以涂黑 s z sz sz 个点。

最终结论,不能涂黑的点数即为树的个数,答案即为总点数减去树的个数。

时间复杂度 O ( n log ⁡ n ) \mathcal{O}(n\log n) O(nlogn),瓶颈在离散化。

C++ 代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n;
map<int,int> mp;
vector<int> g[N<<1];
bool used[N<<1];
int vcnt=0,edgecnt=0;
void dfs(int u){
    used[u]=1;
    vcnt++;
    for(int v:g[u]){
        edgecnt++;
        if(!used[v]){
            dfs(v);
        }
    }
}
int32_t main(){
    int n; cin>>n;
    int cnt=0;//总点数
    for(int i=1;i<=n;i++){
        int x,r; cin>>x>>r;
        int a=x-r,b=x+r;
        if(!mp[a]) mp[a]=++cnt;
        if(!mp[b]) mp[b]=++cnt;
        g[mp[a]].push_back(mp[b]);
        g[mp[b]].push_back(mp[a]);
    }
    int ans=cnt;
    for(int i=1;i<=cnt;i++){
        if(!used[i]){
            vcnt=edgecnt=0;
            dfs(i);
            ans-=(edgecnt/2==vcnt-1);//edgecnt/2 为实际边数,若边数==点数-1,该图为一棵树
        }
    }
    cout<<ans<<endl;
    return 0;
}
相关推荐
冷崖2 小时前
原子锁操作
c++·后端
旖旎夜光6 小时前
C++(17)
c++·学习
Larry_Yanan7 小时前
Qt多进程(三)QLocalSocket
开发语言·c++·qt·ui
superman超哥7 小时前
仓颉语言中元组的使用:深度剖析与工程实践
c语言·开发语言·c++·python·仓颉
LYFlied7 小时前
【每日算法】LeetCode 153. 寻找旋转排序数组中的最小值
数据结构·算法·leetcode·面试·职场和发展
唐装鼠7 小时前
rust自动调用Deref(deepseek)
开发语言·算法·rust
Lucas555555558 小时前
现代C++四十不惑:AI时代系统软件的基石与新征程
开发语言·c++·人工智能
ytttr8738 小时前
MATLAB基于LDA的人脸识别算法实现(ORL数据库)
数据库·算法·matlab
_MyFavorite_8 小时前
cl报错+安装 Microsoft Visual C++ Build Tools
开发语言·c++·microsoft
charlie1145141918 小时前
现代嵌入式C++教程:C++98——从C向C++的演化(2)
c语言·开发语言·c++·学习·嵌入式·教程·现代c++