2019牛客多校第三场

B.Crazy Binary String

传送:https://ac.nowcoder.com/acm/contest/883/B

题意:有一个长度为$n$的‘0’’1‘字符串,询问’0‘,’1‘个数相同的最长的子串和子序列为多长。

数据范围:$1<=n<=10^5$。

分析:首先考虑子序列,那么就是$ans2=min(num[0],num[1])*2$。

将0变为-1,做前缀和。找前缀和相等的跨越长度最大的即可。同时需要特别0位置设为0。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1e5+10;
 4 int num[maxn];
 5 map<int,int> mp;
 6 vector<int> g[2*maxn];
 7 int main(){
 8     string s; 
 9     int n;scanf("%d",&n);
10     cin >> s;
11     int kk=0;
12     for (int i=0;i<n;i++){
13         if (s[i]=='0'){
14             num[i+1]=-1;
15             kk++;
16         }
17         else num[i+1]=1;
18     }
19     kk=min(kk,n-kk);
20     int ans2=kk*2;
21     num[0]=0;
22     for (int i=2;i<=n;i++) num[i]=num[i]+num[i-1];
23     int tot=0;
24     for (int i=0;i<=n;i++){
25         if (mp[num[i]]==0){
26             mp[num[i]]=++tot;
27             g[tot].push_back(i);
28         }
29         else g[mp[num[i]]].push_back(i);
30     } 
31     int ans1=0;
32     for (int i=1;i<=tot;i++){
33         if (g[i].size()>=2){
34             int tmp=g[i][g[i].size()-1]-g[i][0];
35             ans1=max(ans1,tmp);
36         }
37     }
38     printf("%d %d\n",ans1,ans2);
39     return 0;
40 } 
B

F.Planting Trees

传送:https://ac.nowcoder.com/acm/contest/883/F

题意:有一个$n*n$大小的矩阵,求解一个最大的子矩阵,要求这个子矩阵内任意两个数的差的绝对值$<=m$。

数据范围:$1<=n<=500,a_{ij}<=10^5$。

分析:读完题觉得需要维护子矩阵的最大最小值。写了二维线段树,然后枚举起始行和终止行,再尺取法找列。(然而,线段树复杂度太大,tle。

正解是:枚举起始行和终止行,再枚举右边界去找到可行的最小的左边界。

在枚举右边界的同时,维护两个单调队列,维护最大值和最小值,

最小值的单调队列应该为:下标递增,大小递增;最大值的单调队列应该为:下标递增,大小递解。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int INF=2333333;
 4 const int maxn=510;
 5 int a[maxn][maxn],mi[maxn],mx[maxn],q1[maxn],q2[maxn];
 6 int main(){
 7     int t,n,m;scanf("%d",&t);
 8     while (t--){
 9         scanf("%d%d",&n,&m);
10         for (int i=1;i<=n;i++)
11             for (int j=1;j<=n;j++) scanf("%d",&a[i][j]);
12         int ans=0;
13         for (int i=1;i<=n;i++){
14             for (int j=1;j<=n;j++) mi[j]=INF,mx[j]=-INF;
15             for (int j=i;j<=n;j++){
16                 for (int k=1;k<=n;k++){
17                     mi[k]=min(mi[k],a[j][k]);
18                     mx[k]=max(mx[k],a[j][k]);
19                 }
20                 int l1=1,r1=0,l2=1,r2=0;
21                 for (int l=1,r=1;r<=n;r++){
22                     while (l1<=r1 && mx[r]>=mx[q1[r1]]) r1--;
23                     q1[++r1]=r;
24                     while (l2<=r2 && mi[r]<=mi[q2[r2]]) r2--;
25                     q2[++r2]=r;
26                     while (l<=r && mx[q1[l1]]-mi[q2[l2]]>m){
27                         while (l1<=r1 && q1[l1]<=l) l1++;
28                         while (l2<=r2 && q2[l2]<=l) l2++;
29                         l++;
30                     }
31                     ans=max(ans,(j-i+1)*(r-l+1));
32                 }
33             } 
34         }
35         printf("%d\n",ans);
36     }
37     return 0;
38 }
F

另,对面顾老师二维ST表也过了,%%%%%,tttttttql。顾老师代码:

 1 #include<bits/stdc++.h>
 2 #define rep(i,x,y) for(int i=(x);i<=(y);++i)
 3 #define dep(i,x,y) for(int i=(x);i>=(y);--i)
 4 #define pb push_back
 5 #define fr first
 6 #define sc second
 7 using namespace std;
 8 typedef long long ll;
 9 const int N=510;
10 int mx[9][9][N][N],mi[9][9][N][N],a[N][N],rd[N*2];
11 struct fastio{
12     static const int s=1<<24;
13     int p,l;
14     fastio(){p=l=0;}
15     inline char gc(){
16         static char bf[s];
17         if(p==l)p=0,l=fread(bf,1,s,stdin);
18         return p==l?-1:bf[p++];
19     }
20     inline bool read(int&x){
21         char c=gc();
22         while((c<'0'||c>'9')&&~c)c=gc();
23         if(c==-1)return 0;x=0;
24         for(;c>='0'&&c<='9';c=gc())x=x*10+c-'0';
25         return 1;
26     }
27 }io;
28 int cal(int lx,int ly,int rx,int ry){
29     int tx=rd[rx-lx+1],ty=rd[ry-ly+1];
30     int zx=rx-(1<<tx)+1;
31     if(ly==ry)return max(mx[tx][0][lx][ly],mx[tx][0][zx][ly])-
32     min(mi[tx][0][lx][ly],mi[tx][0][zx][ly]);
33     int zy=ry-(1<<ty)+1;
34     return max(max(mx[tx][ty][lx][ly],mx[tx][ty][zx][ly]),
35     max(mx[tx][ty][lx][zy],mx[tx][ty][zx][zy]))-
36     min(min(mi[tx][ty][lx][ly],mi[tx][ty][zx][ly]),
37     min(mi[tx][ty][lx][zy],mi[tx][ty][zx][zy]));
38 }
39 int tot;
40 void sol(){
41     int n,m,ans=0;
42     io.read(n);io.read(m);int t=rd[n];
43     rep(i,1,n)rep(j,1,n)io.read(a[i][j]);
44     rep(i,1,n)rep(j,1,n)mi[0][0][i][j]=mx[0][0][i][j]=a[i][j];
45     rep(i,0,t-1)rep(j,1,n)rep(k,1,n){int r=j+(1<<i);
46         if(r>n){
47             mi[i+1][0][j][k]=mi[i][0][j][k];
48             mx[i+1][0][j][k]=mx[i][0][j][k];
49         }else{
50             mi[i+1][0][j][k]=min(mi[i][0][j][k],mi[i][0][r][k]);
51             mx[i+1][0][j][k]=max(mx[i][0][j][k],mx[i][0][r][k]);
52         }
53     }
54     rep(i,0,t)rep(j,0,t-1)rep(k,1,n)rep(l,1,n){int r=l+(1<<j);
55         if(r>n){
56             mi[i][j+1][k][l]=mi[i][j][k][l];
57             mx[i][j+1][k][l]=mx[i][j][k][l];
58         }else{
59             mi[i][j+1][k][l]=min(mi[i][j][k][l],mi[i][j][k][r]);
60             mx[i][j+1][k][l]=max(mx[i][j][k][l],mx[i][j][k][r]);
61         }
62     }
63     rep(i,1,n)rep(j,1,n){
64         int x=j,mi1=a[i][j],mx1=a[i][j];
65         while(x<=n&&mx1-mi1<=m){
66             ++x;mi1=min(mi1,a[i][x]);mx1=max(mx1,a[i][x]);
67         }
68         ans=max(ans,x-j);--x;
69         rep(k,i+1,n){
70             while(x>=j&&cal(i,j,k,x)>m)--x;
71             if((n-i+1)*(x-j+1)<=ans)break;ans=max(ans,(k-i+1)*(x-j+1));
72         }
73     }printf("%d\n",ans);
74 }
75 int main(){
76     rep(i,0,8)rep(j,(1<<i)+1,2<<i)rd[j]=i;
77     int t;io.read(t);
78     rep(i,1,t)sol();
79 }
F2

H.Magic Line

传送:https://ac.nowcoder.com/acm/contest/883/H

题意:给定平面上的$n$个点,确定一条直线将其划分为数量相等的两部分。

数据范围:$1<=T<=10^5,1<=n<=1000,|x_i,y_i|<=1000$。

分析:移动坐标轴,将所有点放在第一象限,然后根据与x轴的斜率排序,斜率相同根据距离排序。

答案直线一定经过中间两点的中间。

然后在第三象限取一个较远的点,然后另一个点就是中间两点的中位点。(再保证答案为整数即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1005;
 4 typedef long long ll;
 5 struct node{ll x,y,s;} p[maxn];
 6 bool cmp(node a,node b)
 7 {
 8     ll xx=a.x*b.y-b.x*a.y;
 9     return (xx>0 || ((xx==0)&&a.s<b.s));
10 }
11 int main()
12 {
13     int t;scanf("%d",&t);
14     while (t--)
15     {
16         int n;scanf("%d",&n);
17         for (int i=0;i<n;i++)
18         {
19             ll xx,yy;
20             scanf("%lld%lld",&xx,&yy);
21             p[i].x=1ll*3000+xx;
22             p[i].y=1ll*50000+yy;
23             p[i].s=xx*xx+yy*yy;
24         }
25         sort(p,p+n,cmp);
26         node A=p[n/2-1],B=p[n/2];
27         A.x=A.x*2-3000;B.x=B.x*2-3000;
28         A.y=A.y*2-50000;B.y=B.y*2-50000;
29         printf("-3000 -50000 %lld %lld\n",(A.x+B.x)/2,(A.y+B.y)/2);
30     }
31     return 0;
32 }
H

 J.LRU management

传送:https://ac.nowcoder.com/acm/contest/883/J

题意:定义LRU算法如下:

操作0:将名字为$s$,数据为$v$的元素放入列表内。如果存在列表内就将原来的取出添加至最后一个位置,否则直接添加到最后。输出$v$。

操作1:查找名字为$s$的元素的位置$k$,并输出$k+xx$位置的数据$v$。

同时列表只能容纳$m$个元素,如果超出,则弹出最早的元素。

 数据范围:$1<=q,m<=5e5$

分析:list+map模拟。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 struct node{
 4     string s,v;
 5     node(){}
 6     node(string _s,string _v){
 7         s=_s; v=_v; 
 8     }
 9 };
10 int m,q;
11 list<node> lt;
12 unordered_map<string,list<node>::iterator> mp;
13 void solve(string s){
14     char v[20];scanf("%s",v);
15     if (mp.find(s)!=mp.end()){
16         auto it=mp[s];
17         strcpy(v,it->v.data());
18         lt.erase(it);
19     }
20     node tmp; tmp.s=s; tmp.v=v;
21     lt.emplace_back(tmp);
22     mp[s]=prev(lt.end());
23     printf("%s\n",v);
24     if (lt.size()>m){
25         mp.erase(lt.begin()->s);
26         lt.pop_front();
27     }
28 }
29 void solve2(string s){
30     int v;scanf("%d",&v);
31     if (mp.find(s)==mp.end()){
32         printf("Invalid\n");
33         return ;
34     }
35     auto it=mp[s];
36     if (it==lt.begin() && v==-1 || next(it)==lt.end() && v==1){
37         printf("Invalid\n");
38         return ;
39     }
40     if (v==1) it=next(it);
41     else if (v==-1) it=prev(it);
42     printf("%s\n",it->v.data());
43 }
44 int main(){
45     int t,op;scanf("%d",&t);
46     char s[30];
47     while (t--){
48         lt.clear();mp.clear();
49         scanf("%d%d",&q,&m);
50         while (q--){
51             scanf("%d",&op);
52             scanf("%s",&s);
53             if (op==0) solve(s);
54             else solve2(s);
55         }
56     }
57     return 0;
58 } 
J

注:emplace_back优于push_back。用构造函数会比先赋值好再放入费时。

 

posted @ 2019-07-26 00:22  Changer-qyz  阅读(341)  评论(0编辑  收藏  举报