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;
}