2019牛客暑假多校训练营(第三场)

B:求一串01序列的最长子串,要求0、1个数相等。

把1看做-1,求一遍前缀和,如果s[r]-s[l-1]==0,满足条件,记录最开始的是s[l]在的位置。

#include<bits/stdc++.h>
using namespace std;
 
const int N =1000*100+10;
char s[N];
int f[N];
int n;
map<int,int>mp;
 
int main(){
    scanf("%d",&n);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++){
        if(s[i]=='1')f[i]=1;
        else f[i]=-1;
        f[i]+=f[i-1];
    }
    int len=0;
     
    for(int i=1;i<=n;i++){
        if(f[i]==0)len=max(len,i);//f[i]==0出现的位置在最开始
        if(mp[f[i]])len=max(len,i-mp[f[i]]);
        else mp[f[i]]=i;
    }
     
    printf("%d\n",len);
    return 0;
}

H:给出偶数个点,求一条直线,分成两部分,具有相等的点数,用直线上两个点表示直线。

比赛的时候wa哭了,一个错在y轴是从小到上变化,一个错在求平分两点的直线没有加y轴。

按照x轴坐标从小到大,y轴坐标从小到大排,按照象限变化,所以直线要往左偏。

#include<bits/stdc++.h>
using namespace std;
struct p{int x,y;}t[1010];
 
int main(){
    int T; cin>>T;   
    while(T--){
        int n; cin>>n;
        for(int i=1;i<=n;i++)cin>>t[i].x>>t[i].y;
        sort(t+1,t+1+n,[](p a,p b){return a.x==b.x?a.y<b.y:a.x<b.x;});
        int k=n/2;
        cout<<t[k].x-1<<" "<<t[k].y+99959999<<" "<<t[k+1].x+1<<" "<<t[k+1].y-99959999<<" ";
         /*
         if(t[n/2+1].x==t[n/2].x)
            printf("%d %d %d %d\n",t[n/2].x-1,t[n/2].y+999000000,t[n/2+1].x+1,t[n/2+1].y-999000000);
        else{
            printf("%d %d %d %d\n",t[n/2].x,999000000,t[n/2+1].x,-999000000);
        }*/
    }
    return 0;
}

F:给出n*n的方格,不断的取出矩形,最大值减去最小值小于等于m,问能取的矩形最大面积。

枚举上下边界,计算出每列的最大最小值,不断向右扩展的同时判断合法左边界。

用两个单调队列来维护,最小值的单调队列下标增大,所在的列最小值增加。

最大值的单调队列下标增大,所在列最大值减小。

最小值的单调队列下标增大,所在列最小值增大。

注意刚开始,头为1,尾为0

增大右边界时,为维护单调性,取出队尾不满足条件的,不考虑即可

头部两个最小值队列 最大,最大值队列 最小,判断两者大小是否满足题意。

#include<bits/stdc++.h>
using namespace std;
const int inf=1e5+5;
int a[505][505],b[505],c[505];
int t,n,m;
int q1[505],q2[505];
int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        memset(a,0,sizeof(a));
        int ans=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                scanf("%d",&a[i][j]);
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                b[j]=inf;
                c[j]=-inf;
            }
            for(int j=i;j<=n;j++){
                int h1=1,t1=0,h2=1,t2=0,l=1;
                for(int k=1;k<=n;k++){
                    b[k]=min(b[k],a[j][k]);
                    c[k]=max(c[k],a[j][k]);
                    while(h1<=t1&&b[k]<b[q1[t1]]) t1--;
                    q1[++t1]=k;
                    while(h2<=t2&&c[k]>c[q2[t2]]) t2--;
                    q2[++t2]=k;
                    while(l<=k&&(c[q2[h2]]-b[q1[h1]])>m){
                        l++;
                        if(q1[h1]<l) h1++;
                        if(q2[h2]<l) h2++;
                    }
                    //printf("%d %d %d %d\n",i,j,l,k);
                    ans=max(ans,(k-l+1)*(j-i+1));
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

J:模拟 map<string,list的迭代器>

0号操作:若查询的字符串已加入到数组中,就把它取出来,原有值保持不变,压入数组末尾。否则直接加入到末尾,值为输入的v。

1号操作:先得出输入的字符串在数组中的下标k,查询下标为(k+v)的数组元素的值,若k或(k+v)不存在都输出Invalid。

unordered_map比map快四五百毫秒。

#include<bits/stdc++.h>
using namespace std;
int q,m,op,v,k;
char s[20];
struct node
{
    string s;
    int data;
};
list<node> lst;
list<node>::iterator it;
unordered_map<string,list<node>::iterator> mp;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&q,&m);
        mp.clear();
        lst.clear();
        for(int i=0;i<q;i++){
            scanf("%d",&op);
            scanf("%s",s);
            scanf("%d",&v);
            if(op==0){
                if(mp.count(s)==0){
                    if(lst.size()==m){
                        mp.erase(lst.begin()->s);
                        lst.erase(lst.begin());
                    }
                    lst.push_back(node{s,v});
                    it=lst.end();it--;
                    mp[s]=it;
                    printf("%d\n",v);
                }
                else{
                    it=mp[s];
                    printf("%d\n",it->data);
                    lst.erase(it);
                    lst.push_back(node{s,it->data});
                    it=lst.end();it--;
                    mp[s]=it;
                }
            }
            else{
                 if(mp.count(s)==0) printf("Invalid\n");
                 else{
                    it=mp[s];
                     if(v==0){
                        printf("%d\n",it->data);
                     }
                     else if(v==-1){
                        if(it==lst.begin()) printf("Invalid\n");
                        else{
                            it--;
                            printf("%d\n",it->data);
                        }
                     }
                     else{
                        it++;
                        if(it==lst.end()) printf("Invalid\n");
                        else{
                            printf("%d\n",it->data);
                        }
                     }
                 }
            }
        }
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值