[DP 暴力 || ST表 || 单调队列] BZOJ 1499 [NOI2005]瑰丽华尔兹

21 篇文章 0 订阅
9 篇文章 0 订阅

DP方程不难想 主要是优化

首先可以暴力AC 成就感满满

论文:周以苏--反汇编在常数优化因子中的应用


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline void read(char *s){
  char c=nc(); int len=0;
  for (;!(c=='.' || c=='x');c=nc());
  for (;c=='.' || c=='x';s[++len]=c,c=nc()); s[++len]=0;
}

#define Max(a,b) ((a)<(b)?(a)=(b):0)

const int N=205;
const int dx[]={0,-N,N,-1,1};

int n,m,K,T;
char Map[N*N];
int d[40005];
int f[N*N];
int *pt[5][N*N];
int tot[5];

#define P(i,j) (((i)-1)*m+(j))

int main(){
  int ix,iy,il,ir,id;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m); read(ix); read(iy); read(K);
  for (int i=1;i<=n;i++) read(Map+(i-1)*m);
  for (int i=1;i<=K;i++){
    read(il); read(ir); read(id);
    for (int j=il;j<=ir;j++) d[j]=id; T=ir;
  }
  for (int i=1;i<n;i++) for (int j=1;j<=m;j++) if (Map[P(i,j)]!='x') pt[1][++tot[1]]=f+P(i,j); pt[1][++tot[1]]=NULL;
  for (int i=n;i>1;i--) for (int j=1;j<=m;j++) if (Map[P(i,j)]!='x') pt[2][++tot[2]]=f+P(i,j); pt[2][++tot[2]]=NULL;
  for (int i=1;i<=n;i++) for (int j=1;j<m;j++) if (Map[P(i,j)]!='x') pt[3][++tot[3]]=f+P(i,j); pt[3][++tot[3]]=NULL;
  for (int i=1;i<=n;i++) for (int j=m;j>1;j--) if (Map[P(i,j)]!='x') pt[4][++tot[4]]=f+P(i,j); pt[4][++tot[4]]=NULL;
  for (int i=1;i<=n*m;i++) f[i]=-1<<30;
  f[P(ix,iy)]=0;
  for (int t=1;t<=T;t++)
    if (d[t]==1){
      for (int **i=pt[1]+1;*i;i++)
	Max(**i,*(*i+m)+1);
    }else if (d[t]==2){
      for (int **i=pt[2]+1;*i;i++)
	Max(**i,*(*i-m)+1);
    }else if (d[t]==3){
      for (int **i=pt[3]+1;*i;i++)
	Max(**i,*(*i+1)+1);
    }else if (d[t]==4){
      for (int **i=pt[4]+1;*i;i++)
	Max(**i,*(*i-1)+1);
    }
  int Ans=0;
  for (int i=1;i<=n*m;i++) Max(Ans,f[i]);
  printf("%d\n",Ans);
  return 0;
}

正解是方向相同的时间段可以一起处理 可以直接RMQ做 knmlogn

当然最好单调队列 knm


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc());
}

inline void read(char *s){
  char c=nc(); int len=0;
  for (;!(c=='.' || c=='x');c=nc());
  for (;c=='.' || c=='x';s[++len]=c,c=nc()); s[++len]=0;
}

const int N=205;

int n,m,K;
int len[N],d[N];
char Map[N][N];
int f[2][N][N];

int l,r,Q[N];

int main(){
  int ix,iy,il,ir;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m); read(ix); read(iy); read(K);
  for (int i=1;i<=n;i++) read(Map[i]);
  for (int i=1;i<=K;i++)
    read(il),read(ir),read(d[i]),len[i]=ir-il+1;
  int t=0;
  for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) f[0][i][j]=-1<<30;
  f[0][ix][iy]=0;
  for (int k=1;k<=K;k++,t^=1)
    if (d[k]==2){
      for (int j=1;j<=m;j++){
	l=r=-1;
	for (int i=1;i<=n;i++)
	  if (Map[i][j]=='x'){
	    while (l<r) l++;
	  }else{
	    while (l<r && i-Q[l+1]>len[k]) l++;
	    f[t^1][i][j]=f[t][i][j];
	    if (l<r)
	      f[t^1][i][j]=max(f[t^1][i][j],f[t][Q[l+1]][j]-Q[l+1]+i);
	    while (l<r && f[t][i][j]-i>=f[t][Q[r]][j]-Q[r]) r--;
	    Q[++r]=i;
	  }
      }
    }else if (d[k]==1){
      for (int j=1;j<=m;j++){
	l=r=-1;
	for (int i=n;i;i--)
	  if (Map[i][j]=='x'){
	    while (l<r) l++;
	  }else{
	    while (l<r && Q[l+1]-i>len[k]) l++;
	    f[t^1][i][j]=f[t][i][j];
	    if (l<r)
	      f[t^1][i][j]=max(f[t^1][i][j],f[t][Q[l+1]][j]+Q[l+1]-i);
	    while (l<r && f[t][i][j]+i>=f[t][Q[r]][j]+Q[r]) r--;
	    Q[++r]=i;
	  }
      }
    }else if (d[k]==4){
      for (int i=1;i<=n;i++){
	l=r=-1;
	for (int j=1;j<=m;j++)
	  if (Map[i][j]=='x'){
	    while (l<r) l++;
	  }else{
	    while (l<r && j-Q[l+1]>len[k]) l++;
	    f[t^1][i][j]=f[t][i][j];
	    if (l<r)
	      f[t^1][i][j]=max(f[t^1][i][j],f[t][i][Q[l+1]]-Q[l+1]+j);
	    while (l<r && f[t][i][j]-j>=f[t][i][Q[r]]-Q[r]) r--;
	    Q[++r]=j;
	  }
      }
    }else if (d[k]==3){
      for (int i=1;i<=n;i++){
	l=r=-1;
	for (int j=m;j;j--)
	  if (Map[i][j]=='x'){
	    while (l<r) l++;
	  }else{
	    while (l<r && Q[l+1]-j>len[k]) l++;
	    f[t^1][i][j]=f[t][i][j];
	    if (l<r)
	      f[t^1][i][j]=max(f[t^1][i][j],f[t][i][Q[l+1]]+Q[l+1]-j);
	    while (l<r && f[t][i][j]+j>=f[t][i][Q[r]]+Q[r]) r--;
	    Q[++r]=j;
	  }
      }
    }
  int Ans=0;
  for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) Ans=max(Ans,f[t][i][j]);
  printf("%d\n",Ans);
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值