zoukankan      html  css  js  c++  java
  • 牛客练习赛85 B 音乐家的曲调 DP 尺取

    传送门

    题意:

    给出一个全由小写字母组成的字符串,让你找出三个区间,这三个区间不能重合,并且每个区间内1,每个字母出现的顺序不能超过m次,找出使得这三个区间长度之和最大的情况

    题解:

    1,如何找出最长的一个区间使得每个字母出现的次数不超过m次

    用一个数组记录26个字母分别出现多少次,再用一个指针记录在当前位置下,在保证每个字母出现次数都不超过m的条件下,区间往左最长能有多长

    当遍历到第i位,某个字母出现了m+1次时,记此时上述指针指向的位置是k,则令endp[k]=i-1,然后k++

    i遍历完成整个字符串后,令当前k右边所有字符的right_broad都为字符串最末一个字符的位置

    endp[i]-i+1中的最大值就是最长的区间

    2,如何找出三个区间使得总的区间和最大

    从后向前dp

    第一次dp寻找在仅保留第i位及其右边的字符的情况下,最长的符合条件的区间

    dp1[i]=max(dp1[i+1],endp[i]-i+1);

    第二次dp寻找在仅保留第i位及其右边的字符的情况下,两个符合条件的区间的长度和的最大值

    dp2[i]=max(dp2[i+1],endp[i]-i+1+dp1[endp[i]+1]);

    这个状态转移公式解释一下,从第i位起的那个符合条件的区间要全取走,然后就剩下了从第endp[i]+1位起右边的剩余字符了,这时候dp1里面存储的就是答案

    第三次dp同理

    dp3[i]=max(dp3[i+1],endp[i]-i+1+dp2[endp[i]+1]);

    #include<iostream>
    #include<string>
    #include<queue>
    /*struct Point{
        int id;
        char c;
    }
    Point point(int a,char b){
        Point tmp;
        tmp.id=a;
        tmp.c=b;
        return tmp;
    };*/
    using namespace std;
    int alphabet[200];
    int endp[10000007];
    int dp1[10000007],dp2[10000007],dp3[10000007];
    string s;
    int main(){
        int n,m;
        cin>>n>>m;
        cin>>s;
        int l=n;
        queue<int> que[200];
        for(int i=0;i<l;i++){
            if(alphabet[s[i]]==m){
                endp[que[s[i]].front()]=i-1;
                alphabet[s[i]]--;
                que[s[i]].pop();
            }
            alphabet[s[i]]++;
            que[s[i]].push(i);
        }
        for(int i='a';i<='z';i++){
            while(!que[i].empty()){
                endp[que[i].front()]=l-1;
                que[i].pop();
            }
        }
        for(int i=l-2;i>=0;i--){
            endp[i]=min(endp[i],endp[i+1]);
        }
        /*for(int i=0;i<l;i++){
            cout<<endp[i]<<" ";
        }
        cout<<endl;*/
        //int dp1=l-1,dp2=l-1,dp3=l-1;
        for(int i=l-1;i>=0;i--){
            dp1[i]=max(dp1[i+1],endp[i]-i+1);
        }
        for(int i=l-1;i>=0;i--){
            dp2[i]=max(dp2[i+1],endp[i]-i+1+dp1[endp[i]+1]);
        }
        for(int i=l-1;i>=0;i--){
            dp3[i]=max(dp3[i+1],endp[i]-i+1+dp2[endp[i]+1]);
        }
        cout<<dp3[0]<<endl;
        return 0;
    }
  • 相关阅读:
    es6 简介
    npm 快速开发技巧
    css清除浮动方法
    mui 总结
    7种 JS 创建对象的经典方式
    JavaScript 的 this 原理
    使用定时器
    dom 操作及方法
    JavaScript的6种继承方式及其优缺点
    贪吃蛇游戏代码
  • 原文地址:https://www.cnblogs.com/isakovsky/p/14932857.html
Copyright © 2011-2022 走看看