Loading

【比赛】这次应该叫高二上几调 (部分)

T2 biology

很容易想到按a[i][j]分层

但是极限复杂度 $o(n^2m^2/4)$ (基本不等式啊喂)

发现这里是求曼哈顿距离最大 

可以用一个很nb的优化

即:不合法一定不做贡献

(如果求曼哈顿距离最小则不满足该优化原则)

想要优化复杂度一定要分方向 去绝对值

但是怎么区分候选点和当前点的位置关系

发现 四个方向有四种计算方式

在错误的方向计算出来的贡献一定会比正确的方向计算出来的小

例:候选点在左上 以右下方式计算得出的贡献小于左上做出的贡献

(曼哈顿距离一个方向出负数了)

 所以我们不考虑候选点与当前点位置关系

四个方向都维护一下

反正不合法的不做贡献

#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);
}
View Code

C. english

可能会想到维护一个数p的左右区间端点l,r(单调栈)

从l到p-1选出一个l1,p+1到r选出一个r1

则区间(l1,r1) 最大值即p

然后你发现你不知道接下来怎么搞了

然后你发现 区间构成01trie关系

按区间维护每位1个数总和 用启发式合并 可解决opt1

至于opt2 哦我暂时不会……

以下opt1代码 如果不该成排序处理似乎会被递增数据爆栈(递归几万次)

#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);
    }
}
View Code

 

posted @ 2022-07-13 21:05  hzoi_Sakura  阅读(33)  评论(0编辑  收藏  举报