BZOJ3873 : [Ahoi2014]拼图

如果答案在某个碎片内部,那么直接悬线法解决,时间复杂度$O(n\sum)$。

 

如果$n$比较大,那么$\sum$比较小。

求出每个点向上能延伸的长度,枚举每个点向上这条线段作为短板。

算出完全可选的碎片的长度之和以及不能完全选,左边右边最大次大延伸距离,更新答案。

时间复杂度$O(n\sum^2)$。

 

如果$n$比较小,那么暴力枚举上下边界,计算答案方法同上。

时间复杂度$O(n^2\sum)$。

 

总时间复杂度$O(n\sum\sqrt{n\sum})$。

 

#include<cstdio>
const int N=100010,M=320;
int T,num,n,m,i,j,k,x,cnt,FL0,GL,FL1,FR0,GR,FR1,ans;
inline void up(int&f0,int&g0,int&f1,int x,int y){
  if(x>f0){f1=f0,f0=x,g0=y;return;}
  if(x>f1)f1=x;
}
inline void uans(int x){if(ans<x)ans=x;}
namespace NSMALL{
int st[N],en[N],f[N],g[N],w[N];char a[M][N],s[N];
void solve(){
  for(i=1;i<=num;i++){
    scanf("%d",&x);
    st[i]=m+1;
    en[i]=m+x;
    for(j=1;j<=n;j++){
      scanf("%s",s);
      for(k=0;k<x;k++)a[j][k+st[i]]=s[k]-'0';
    }
    m+=x;
  }
  for(i=1;i<=m;i++)f[i]=1,g[i]=m,w[i]=0;
  for(i=1;i<=n;i++){
    for(GL=j=1;j<=m;j++)if(!a[i][j]){
      w[j]++;
      if(GL>f[j])f[j]=GL;
    }else w[j]=0,f[j]=1,g[j]=m,GL=j+1;
    for(GR=j=m;j;j--)if(!a[i][j]){
      if(GR<g[j])g[j]=GR;
      uans(w[j]*(g[j]-f[j]+1));
    }else GR=j-1;
  }
  for(i=1;i<=n;i++){
    for(k=1;k<=num;k++)f[k]=en[k],g[k]=st[k];
    for(j=i;j<=n;j++){
      cnt=FL0=GL=FL1=FR0=GR=FR1=0;
      for(k=1;k<=num;k++){
        for(x=st[k];x<=en[k];x++)if(a[j][x])break;
        if(f[k]>x-1)f[k]=x-1;
        for(x=en[k];x>=st[k];x--)if(a[j][x])break;
        if(g[k]<x+1)g[k]=x+1;
        if(f[k]==en[k]){cnt+=en[k]-st[k]+1;continue;}
        up(FL0,GL,FL1,f[k]-st[k]+1,k);
        up(FR0,GR,FR1,en[k]-g[k]+1,k);
      }
      if(GL!=GR)uans((j-i+1)*(cnt+FL0+FR0));else{
        uans((j-i+1)*(cnt+FL0+FR1));
        uans((j-i+1)*(cnt+FL1+FR0));
      }
    }
  }
}
}
namespace NBIG{
int st[M],en[M],f[M],g[M],w[M];char a[N][M],s[M];
void solve(){
  for(i=1;i<=num;i++){
    scanf("%d",&x);
    st[i]=m+1;
    en[i]=m+x;
    for(j=1;j<=n;j++){
      scanf("%s",s);
      for(k=0;k<x;k++)a[j][k+st[i]]=s[k]-'0';
    }
    m+=x;
  }
  for(i=1;i<=m;i++)f[i]=1,g[i]=m,w[i]=0;
  for(i=1;i<=n;i++){
    for(GL=j=1;j<=m;j++)if(!a[i][j]){
      w[j]++;
      if(GL>f[j])f[j]=GL;
    }else w[j]=0,f[j]=1,g[j]=m,GL=j+1;
    for(GR=j=m;j;j--)if(!a[i][j]){
      if(GR<g[j])g[j]=GR;
      uans(w[j]*(g[j]-f[j]+1));
    }else GR=j-1;
  }
  for(i=1;i<=m;i++)w[i]=0;
  for(i=1;i<=n;i++){
    for(j=1;j<=m;j++)if(a[i][j])w[j]=0;else w[j]++;
    for(j=1;j<=m;j++)if(w[j]){
      cnt=FL0=GL=FL1=FR0=GR=FR1=0;
      for(k=1;k<=num;k++){
        for(x=st[k];x<=en[k];x++)if(w[x]<w[j])break;
        f[k]=x-1;
        for(x=en[k];x>=st[k];x--)if(w[x]<w[j])break;
        g[k]=x+1;
        if(f[k]==en[k]){cnt+=en[k]-st[k]+1;continue;}
        up(FL0,GL,FL1,f[k]-st[k]+1,k);
        up(FR0,GR,FR1,en[k]-g[k]+1,k);
      }
      if(GL!=GR)uans(w[j]*(cnt+FL0+FR0));else{
        uans(w[j]*(cnt+FL0+FR1));
        uans(w[j]*(cnt+FL1+FR0));
      }
    }
  }
}
}
int main(){
  scanf("%d",&T);
  while(T--){
    scanf("%d%d",&num,&n);
    m=ans=0;
    if(n<=315)NSMALL::solve();else NBIG::solve();
    printf("%d\n",ans);
  }
  return 0;
}

  

posted @ 2016-06-26 00:46  Claris  阅读(316)  评论(0编辑  收藏  举报