• 2022杭电多校3——补题


    Cyber Language

    可以用stringstream每次得到一个单词

    inline void solve(){
        string s; getline(cin,s);
        stringstream ss; ss<<s;
        string str;
        while(ss>>str){
            char t=str[0];
            t=t-'a'+'A';
            cout<<t;
        }
        cout<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Package Delivery(贪心)

    一开始当成区间覆盖做了,发现用一种情况不能被考虑到

    按照区间覆盖排完序之后,因为是按照右端点递增排序,所以会有这种情况发生:

    [1,4] [5,6] [2,8]

    一开始选择了4这个点,但是到第二个区间就会转移到6这个点,第三个区间可以放在4这个点,所以就会导致答案变差

    可以将每次取得点存进set中,若选则的点与当前区间为无交集,则插入一个新的点,否则在set中找到第一个大于等于左区间的点拿快递一定更优

    注意特判k=1的情况,因为我是先插入了一个点,后面会先++再判断是否等于k(感谢恒哥!)

    const int N=1e6+10;
    int n,m;
    PII g[N];
    bool cmp(PII a,PII b){
        if(a.r==b.r) return a.l<b.l;
        return a.r<b.r;
    }
    inline void solve(){
       cin>>n>>m;
       for(int i=0;i<n;i++){
            int a,b; cin>>a>>b;
            g[i]={a,b};
       }
       if(m==1) cout<<n<<endl;
       else{
           sort(g,g+n,cmp);
           //for(int i=0;i
           set<int>s;map<int,int>mp;
           s.insert(0);
           int ans=1,pos=g[0].r;
           mp[pos]=1,s.insert(pos);
           for(int i=1;i<n;i++){
               // cout<
                if(g[i].l>*(--s.end())){
                    pos=g[i].r;
                    ans++;
                    mp[pos]=1,s.insert(pos);
                }
                else{//g[i].l<=pos
                    int now=*s.lower_bound(g[i].l);
                    if(now<=g[i].r){
                        mp[now]++;
                        if(mp[now]==m){
                            mp.erase(now);
                            s.erase(now);
                        }
                    }
                    else{
                        pos=g[i].r;
                        ans++;
                        mp[pos]=1,s.insert(pos);
                    }
                }
           }
           cout<<ans<<endl;
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    Two Permutations(dp)

    f[i][j]表示在s中凑到第i位,第i位选P/Q中的方案数(学习自恒哥)

    const int N=3e5+10;
    int n;
    int a[N],b[N],s[2*N];
    int posa[N],posb[N];
    int f[2*N][3];
    inline void solve(){
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i],posa[a[i]]=i;
        for(int i=1;i<=n;i++) cin>>b[i],posb[b[i]]=i;
        for(int i=1;i<=2*n;i++) cin>>s[i];
        if(a[1]==s[1]) f[1][0]=1;
        else f[1][0]=0;
        if(b[1]==s[1]) f[1][1]=1;
        else f[1][1]=0;
        for(int i=2;i<=2*n;i++){
            f[i][1]=f[i][0]=0;
            
            int last=posa[s[i-1]];
            if(last>=1&&last<n&&a[last]==s[i-1]&&a[last+1]==s[i]){
                f[i][0]+=f[i-1][0];
            }
            
            last=i-posb[s[i-1]];
            if(last>=1&&last<=n&&a[last]==s[i]){
                f[i][0]+=f[i-1][1];
            }
            
            last=posb[s[i-1]];
            if(last>=1&&last<n&&b[last]==s[i-1]&&b[last+1]==s[i]){
                f[i][1]+=f[i-1][1];
            }
            
            last=i-posa[s[i-1]];
            if(b[last]==s[i]){
                f[i][1]+=f[i-1][0];
            }
            f[i][1]%=mod;
            f[i][0]%=mod;
        }
        cout<<(f[2*n][1]+f[2*n][0])%mod<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    Boss Rush(二分+状压dp+记忆化搜索)

    物品数较小,可以用状压枚举出所有情况

    找最小时间二分

    不能枚举出每种技能的使用先后顺序,所以可以用记忆化搜索求出每种情况下造成的最大伤害

    const int N=20,M=1e5+10;
    int n,m,mid,l,r;
    int f[1<<N];
    int s[N][M],t[N],len[N];
    int dfs(int u){
        if(f[u]!=-1) return f[u];//剪枝
        int time=0,res=0;
        for(int i=0;i<n;i++){
            if(u>>i&1) time+=t[i+1];
        }
        if(time>mid) return f[u]=0;//mid不能小于总冷却时间
        for(int i=0;i<n;i++){
            if(!(u>>i&1)){
                res=max(res,s[i+1][min(len[i+1],mid-time)]+dfs(u|(1<<i)));//记录最大伤害
            }
        }
        return f[u]=res;
    }
    bool check(){
        for(int i=0;i<(1<<n);i++) f[i]=-1;
        return dfs(0)>=m;
    }
    inline void solve(){
        cin>>n>>m;
        l=r=0;
        for(int i=1;i<=n;i++){
            cin>>t[i]>>len[i];
            r+=max(t[i],len[i]);
            for(int j=1;j<=len[i];j++) cin>>s[i][j],s[i][j]+=s[i][j-1];
        }
        int ans=inf;
        while(l<=r){
            mid=l+r>>1;
            if(check()) ans=min(ans,mid),r=mid-1;
            else l=mid+1;
        }
        if(ans==inf) cout<<-1<<endl;
        else cout<<ans-1<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    Taxi(二分)

    为满足二段性,应先对w进行排序
    在这里插入图片描述

    我们可以利用上述公式O(1)求出排序后的所有点与(x,y)的最大距离dist

    可以二分到达哪个点mid能得到最大的优惠

    d i s t [ m i d , n ] > w m i d dist_{[mid,n]}>w_{mid} dist[mid,n]>wmid时,最大优惠是 w m i d w_{mid} wmid,向右二分

    否则向左二分

    const int N=1e5+10;
    int n,m;
    int a[N],b[N],c[N],d[N];
    struct P{
        int x,y,w;
        bool operator<(const P&t)const{
            return w<t.w;
        }
    }p[N];
    int ans,x,y;
    bool check(int mid){
        int dist=0;
        dist=max(dist,x+y+a[mid]);
        dist=max(dist,x-y+b[mid]);
        dist=max(dist,-x+y+c[mid]);
        dist=max(dist,-x-y+d[mid]);
        ans=max(ans,min(p[mid].w,dist));
        return dist>=p[mid].w;
    }
    inline void solve(){
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            int x,y,z; cin>>x>>y>>z;
            p[i]={x,y,z};
        }
        sort(p+1,p+n+1);
        a[n+1]=b[n+1]=c[n+1]=d[n+1]=-inf;
        for(int i=n;i>=1;i--){
            int x=p[i].x,y=p[i].y;
            a[i]=max(a[i+1],-x-y);
            b[i]=max(b[i+1],-x+y);
            c[i]=max(c[i+1],x-y);
            d[i]=max(d[i+1],x+y);
        }
        while(m--){
            cin>>x>>y;
            int l=1,r=n;ans=0;
            while(l<=r){
                int mid=l+r>>1;
                if(check(mid)) l=mid+1;
                else r=mid-1;
            }
            cout<<ans<<endl;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    SpringMVC的执行流程及初始化流程
    设计模式-访问者模式-笔记
    BUUCTF——Basic题解
    基于51单片机的智能台灯设计
    LeetCode 每日一题 2024/4/15-2024/4/21
    flutter 手机卡住,需要等待,主线程被占用
    [LeetCode解题报告] 871. 最低加油次数
    面试突击44:volatile 有什么用?
    基于C#开发web网页管理系统模板流程-主界面密码维护功能完善
    4.2冰达机器人:视觉实例-机器人视觉循线、视觉实例-调整循线颜色
  • 原文地址:https://blog.csdn.net/ZVAF_/article/details/126020203