【比赛】这次应该叫高二上几调 (部分)
T2 biology
很容易想到按a[i][j]分层
但是极限复杂度 $o(n^2m^2/4)$ (基本不等式啊喂)
发现这里是求曼哈顿距离最大
可以用一个很nb的优化
即:不合法一定不做贡献
(如果求曼哈顿距离最小则不满足该优化原则)
想要优化复杂度一定要分方向 去绝对值
但是怎么区分候选点和当前点的位置关系
发现 四个方向有四种计算方式
在错误的方向计算出来的贡献一定会比正确的方向计算出来的小
例:候选点在左上 以右下方式计算得出的贡献小于左上做出的贡献
(曼哈顿距离一个方向出负数了)
所以我们不考虑候选点与当前点位置关系
四个方向都维护一下
反正不合法的不做贡献
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define Sa Sakura #define Re register int #define _ putchar(' ') #define el putchar('\n') #define int long long #define maxn 4000010 using namespace std; inline int read(){ int f=0,x=0;char c=getchar(); while(c<'0'||c>'9') f|=c=='-',c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); return f?-x:x; } inline void ot(int x){ if(x<0) putchar('-'),x=-x; if(x>9) ot(x/10);putchar(x%10|48); } struct node{ int a,b,x,y,an; #define a(i) q[i].a #define b(i) q[i].b #define x(i) q[i].x #define y(i) q[i].y #define an(i) q[i].an }q[maxn]; inline bool cmp(node A,node B){ return A.a<B.a; } int n,m,l[maxn],r[maxn],tot,ans,Min1[maxn],Min2[maxn],Min3[maxn],Min4[maxn]; bool spy(){ for(Re i=1;i<=n*m;i++) if(a(i)!=(i-1)/n+1) return false; return true; } void sps(){ // cout<<"md 终于打完了"<<endl; for(Re i=2;i<=n;i++){ int maxx=-1; for(Re j=1;j<=m;j++){ maxx++; maxx=max(maxx,an((i-2)*n+j)+1); an((i-1)*n+j)=max(maxx+b((i-1)*n+j),an((i-1)*n+j)); } maxx=-1; for(Re j=m;j>=1;j--){ maxx++; maxx=max(maxx,an((i-2)*n+j)+1); an((i-1)*n+j)=max(maxx+b((i-1)*n+j),an((i-1)*n+j)); ans=max(an((i-1)*n+j),ans); } } ot(ans); } main(){ // freopen("biology3.in","r",stdin); n=read(),m=read(); for(Re i=1;i<=n;i++) for(Re j=1;j<=m;j++){ int id=(i-1)*n+j; a(id)=read(); if(!a(id)) a(id)=99999999; x(id)=i,y(id)=j; } for(Re i=1;i<=n;i++) for(Re j=1;j<=m;j++){ int id=(i-1)*n+j; b(id)=read(); an(id)=b(id); ans=max(ans,b(id)); } if(spy()){ sps(); return 0; } sort(q+1,q+n*m+1,cmp); a(0)=a(n*m+1)=-1; for(Re i=1;i<=n*m;i++){ if(a(i)!=a(i-1)) l[++tot]=i; if(a(i)!=a(i+1)) r[tot]=i; } if(a(n*m)==99999999) tot--; // for(Re i=1;i<=tot;i++) ot(r[i]-l[i]+1),_;el; for(Re i=l[1];i<=r[1];i++){ Min1[1]=min(Min1[1],x(i)+y(i)-an(i)); Min2[1]=min(Min2[1],x(i)-y(i)-an(i)); Min3[1]=min(Min3[1],-x(i)+y(i)-an(i)); Min4[1]=min(Min4[1],-x(i)-y(i)-an(i)); } // for(Re i=1;i<=tot;i++){ // ot(i),el; // for(Re j=l[i];j<=r[i];j++) ot(x(j)),_,ot(y(j)),_,ot(an(j)),el; // // ot(Min1[i]),_,ot(Min2[i]),_,ot(Min3[i]),_,ot(Min4[i]),el; // } for(Re i=2;i<=tot;i++){ // ot(i),el; Min1[i]=Min2[i]=Min3[i]=Min4[i]=99999999; for(Re j=l[i];j<=r[i];j++){ an(j)=max(an(j),b(j)+x(j)+y(j)-Min1[i-1]); an(j)=max(an(j),b(j)+x(j)-y(j)-Min2[i-1]); an(j)=max(an(j),b(j)-x(j)+y(j)-Min3[i-1]); an(j)=max(an(j),b(j)-x(j)-y(j)-Min4[i-1]); Min1[i]=min(Min1[i],x(j)+y(j)-an(j)); Min2[i]=min(Min2[i],x(j)-y(j)-an(j)); Min3[i]=min(Min3[i],-x(j)+y(j)-an(j)); Min4[i]=min(Min4[i],-x(j)-y(j)-an(j)); ans=max(ans,an(j)); } } // for(Re i=1;i<=tot;i++){ // ot(i),el; // for(Re j=l[i];j<=r[i];j++) ot(x(j)),_,ot(y(j)),_,ot(an(j)),el; // ot(Min1[i]),_,ot(Min2[i]),_,ot(Min3[i]),_,ot(Min4[i]),el; // } ot(ans); }
C. english
可能会想到维护一个数p的左右区间端点l,r(单调栈)
从l到p-1选出一个l1,p+1到r选出一个r1
则区间(l1,r1) 最大值即p
然后你发现你不知道接下来怎么搞了
然后你发现 区间构成01trie关系
按区间维护每位1个数总和 用启发式合并 可解决opt1
至于opt2 哦我暂时不会……
以下opt1代码 如果不该成排序处理似乎会被递增数据爆栈(递归几万次)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define Sa Sakura #define Re register int #define _ putchar(' ') #define el putchar('\n') #define maxn 1000100 #define int long long #define mod 1000000007 using namespace std; inline int read(){ int f=0,x=0;char c=getchar(); while(c<'0'||c>'9') f|=c=='-',c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); return f?-x:x; } inline void ot(int x){ if(x<0) putchar('-'),x=-x; if(x>9) ot(x/10);putchar(x%10|48); } map<pair<int,int>,int> h; int n,opt,ans1,ans2; int s[maxn],top; int a[maxn],l[maxn],r[maxn],lc[maxn],rc[maxn],rt; int f[maxn][22],g[maxn][22]; int build(int l,int r){ int p=h[make_pair(l,r)]; // ot(p),_,ot(l),_,ot(r),el; if(p!=l) lc[p]=build(l,p-1); if(p!=r) rc[p]=build(p+1,r); for(Re i=1;i<=20;i++){ f[p][i]=g[p][i]=bool(a[p]&(1<<i-1)); f[p][i]+=f[lc[p]][i]; f[p][i]+=f[rc[p]][i]; } return p; } void solve1(int p){ if(!p) return; solve1(lc[p]); solve1(rc[p]); int d1=p-l[p],d2=r[p]-p,d=r[p]-l[p]+1; for(Re i=1;i<=20;i++){ int num=f[lc[p]][i]*(d2-f[rc[p]][i])+(d1-f[lc[p]][i])*f[rc[p]][i]+g[p][i]*(d-f[p][i])+(1-g[p][i])*f[p][i]; num%=mod; ans1+=num*(1<<i-1)*a[p]%mod; // ot(p),_,ot(i),_,ot(num),el; ans1%=mod; } } main(){ // freopen("english4.in","r",stdin); n=read(),opt=read(); for(Re i=1;i<=n;i++) a[i]=read(); a[0]=a[n+1]=999999; for(Re i=1;i<=n+1;i++){ while(top&&a[s[top]]<a[i]) r[s[top--]]=i-1; s[++top]=i; } top=0; for(Re i=n;i>=0;i--){ while(top&&a[s[top]]<=a[i]) l[s[top--]]=i+1; s[++top]=i; } for(Re i=1;i<=n;i++) h.insert(make_pair(make_pair(l[i],r[i]),i)); // for(Re i=1;i<=n;i++) ot(i),_,ot(l[i]),_,ot(r[i]),_,ot(lc[i]),_,ot(rc[i]),el; rt=build(1,n); // for(Re i=1;i<=n;i++){ // ot(i),el; // for(Re j=1;j<=20;j++) ot(f[i][j]),_;el; // } if(opt!=2){ solve1(rt); ot(ans1); } }