At408 ABCDE

A.Timeout


原题链接

题意简述

满足任意时刻序列 \(a_{i+1}-a_{i} \leq s\) 输出\(yes\),否则\(no\),注意 \(0-idx\)

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
int main(){
    int n,s;cin>>n>>s;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    bool f=1;
    for(int i=0;i<n;i++){
        if(a[i+1]-a[i]>s) f=0; 
    }
    if(f) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
    return 0;
}

B.Compression


原题链接

题意简述

对输入序列升序排序后去重

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
int main(){
    int n;cin>>n;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a.begin()+1,a.end());
    a.erase(unique(a.begin()+1,a.end()),a.end());
    cout<<a.size()-1<<endl;
    for(int i=1;i<a.size();i++) cout<<a[i]<<' ';
    cout<<endl;
    return 0;
}

C.Not All Covered


原题链接

题意简述

\(n\) 条线段,第 \(i\)条线段覆盖 \(l_i,r_i\)的区间,求区间最小被覆盖的点被覆盖的次数

解题思路

范围十分小,甚至不需要离散化,直接差分后前缀和统计即可

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
int main(){
    int n,m;cin>>n>>m;
    vector<int>a(n+2);
    for(int i=1;i<=m;i++){
        int l,r;cin>>l>>r;
        ++a[l],--a[r+1];
    }
    for(int i=1;i<=n;i++) a[i]+=a[i-1];
    ll minl=INT_MAX;
    for(int i=1;i<=n;i++) minl=min(minl,(ll)a[i]);
    cout<<minl<<endl;
    return 0;
}

D.Flip to Gather


原题链接

题意简述

维护01字符串,进行任意次操作,每次操作可以修改任意一个位置的 \(0\) 变成 \(1\),或 \(1\) 变成 \(0\) 求满足使得01串中的连续1区间最大出现1次的极小修改次数。

解题思路1

不妨考虑\(01\)串最后状态的可能性,全0,前缀0后跟随若干1,前缀0后跟随若干1后跟随若干0,不妨根据这三种状态规划动态规划数组,\(dp_{i,0}\)表示前 \(i\) 个位置是全0的最小操作次数,\(dp_{i,1}\)表示前 \(i\) 个位置是前缀0和若干1组合的最小操作次数,\(dp_{i,2}\) 表示前
\(i\) 个位置是前缀0和若干1组合再加上若干0的最小操作次数,则有状态转移方程 \(dp_{i,0}=dp_{i-1,0}+(s_i \neq 0)\),\(dp_{i,1}=min(dp_{i-1,0},dp_{i-1,1})+(s_i \neq 1)\),\(dp_{i,2}=min(dp_{i-1,1},dp_{i-1,2})+(s_i \neq 0)\).

AC code1

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
void solve(){
    int n;cin>>n;
    string s;cin>>s;
    vector<vector<ll> >dp(n+1,vector<ll>(3,INT_MAX));
    dp[0][0]=0;
    for(int i=1;i<=n;i++){
        dp[i][0]=dp[i-1][0]+(s[i-1]!='0');
        dp[i][1]=min(dp[i-1][0],dp[i-1][1])+(s[i-1]!='1');
        dp[i][2]=min(dp[i-1][1],dp[i-1][2])+(s[i-1]!='0');
    }
    cout<<min({dp[n][0],dp[n][1],dp[n][2]})<<endl;
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    int T;cin>>T;
    while(T--) solve();
    return 0;
}

解题思路2

注意到,最终状态一定是中间一段 \(1\) 两边为 \(0\) ,其中中间1的个数可以取 \([0,n]\),考虑对于每个 \([l_i,r_i]\)是1的区间如何修改,使得满足条件,显然有操作次数等于区间内的 \(0\) 的个数和区间外 \(1\) 的个数之和,假设 \(sum_0\) 是前缀0的个数,\(sum_1\) 是前缀1的个数,则当前修改次数为 \(sum_{0,r}-sum_{0,l-1}+sum_{1,n}-(sum_{1,r}-sum_{1,l-1})\),记 \(C_i=sum_{0,i}-sum_{1,i}\),则有修改次数为 \(C_r-C_{l-1}+sum_{1,n}\),又因为对一个字符串 \(sum_{1,n}\)的值是固定的,那么我们只需要枚举 \(C_r-C_{l-1}\),记录最小值即可

AC code2

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
void solve(){
    int n;cin>>n;
    string s;cin>>s;
    int Sum=count(s.begin(),s.end(),'1');
    int pre=0;
    int res=0;
    for(char &c:s){
        pre=min(0,pre)+(c=='1'?-1:1);
        res=min(res,pre);
    }
    cout<<Sum+res<<endl;
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    int T;cin>>T;
    while(T--) solve();
    return 0;
}

E.Minimum OR Path


原题链接

题意简述

给定一个 \(n\) 个点 \(m\) 条边的无向联通图,保证无自环,求从 \(1\)\(n\) 的所有简单路径中,对其边权连续按位或的最小值。

解题思路

因为是位运算,可以拆位考虑。又要求最小值,不妨贪心的想,最开始初始化 \(ans\) 为一个极大值 ,其二进制为 \(111...1\) ,然后从高位逐位判断,如果当前位是 \(0\) 是否可以更新一条从 \(1\)\(n\) 的通路。具体做法是,遍历每一条边,判断当前边权是不是 \(ans\) 的子集,是则连边,最后有通路则这一位为 \(0\),否则为 \(1\),

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
struct DSU{
    vector<int>f,siz;
    DSU(int n){
        init(n);
    }
    void init(int n){
        f.resize(n+1);
        siz.assign(n+1,1);
        iota(f.begin(),f.end(),0);
    }
    int find(int x){
        return x==f[x]?x:f[x]=find(f[x]);
    }
    bool Union(int x,int y){
        int fx=find(x),fy=find(y);
        if(fx==fy) return 0;
        f[fx]=fy;
        siz[fx]+=siz[fy];
        return 1;
    }
    bool Same(int x,int y){
        return find(x)==find(y);
    }
};
struct edge{
    int x,y;ll w;
};
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    int n,m;cin>>n>>m;
    vector<edge>a(m+1);
    for(int i=1;i<=m;i++) cin>>a[i].x>>a[i].y>>a[i].w;
    int ans=(1<<30)-1;
    for(int k=29;k>=0;k--){
        int t=(ans^(1<<k));
        DSU dsu(n);
        for(int i=1;i<=m;i++){
            if((a[i].w|t)==t) dsu.Union(a[i].x,a[i].y);
        }
        if(dsu.Same(1,n)) ans=t;
    }
    cout<<ans<<endl;
}
posted @ 2025-06-01 00:35  usedchang  阅读(30)  评论(0)    收藏  举报