bzoj1499 [NOI2005]瑰丽华尔兹
很容易想出O(NMT)的算法,枚举时间,然后枚举位置,转移就好了,大概是f[t][i][j]=max(f[t-1][i][j],f[t-1][i-dx[t]][j-dy[t]]+1) dx,dy表示某时刻的滑行方向。这样显然过不了,但是看到每一时间段滑行的方向是相同的,也就是只会在一条直线上转移,于是可以用单调队列维护这一条线上的最优值。当某位置是障碍的时候,这个点不能转移或者被转移,那么清空队列;当转移长度大于时间段长度的时候,当前值不合法,需要后移队首指针;当不动比队尾还要优的时候,队尾永远不可能成为最优值,那么前移队尾指针。这样枚举时间段,枚举位置就可以了,O(NMK)。
adv1900
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 220 7 #define inf 2147483647 8 using namespace std; 9 char map[maxn][maxn]; 10 int f[2][maxn][maxn],q[maxn]; 11 int n,m,p,sx,sy,st,ed,dir,now,last,ans; 12 13 int main() 14 { 15 scanf("%d%d%d%d%d",&n,&m,&sx,&sy,&p); 16 for (int i=1;i<=n;i++) scanf("%s",map[i]+1); 17 now=1; last=0; 18 memset(f,200,sizeof(f)); 19 if (map[sx][sy]!='x') f[now][sx][sy]=0; 20 for (int k=1;k<=p;k++) 21 { 22 scanf("%d%d%d",&st,&ed,&dir); 23 int len=ed-st+1; 24 now^=1; last^=1; 25 memset(f[now],200,sizeof(f[now])); 26 switch (dir) 27 { 28 case 1: 29 for (int j=1;j<=m;j++) 30 { 31 int head=1,tail=0; 32 for (int i=n;i>=1;i--) 33 { 34 f[now][i][j]=f[last][i][j]; 35 if (map[i][j]=='x') head=1,tail=0; 36 while (head<=tail&&f[last][i][j]>f[last][q[tail]][j]+q[tail]-i) tail--; 37 q[++tail]=i; 38 while (head<=tail&&i+len<q[head]) head++; 39 if (head<=tail) f[now][i][j]=max(f[now][i][j],f[last][q[head]][j]+q[head]-i); 40 } 41 } 42 break; 43 case 2: 44 for (int j=1;j<=m;j++) 45 { 46 int head=1,tail=0; 47 for (int i=1;i<=n;i++) 48 { 49 f[now][i][j]=f[last][i][j]; 50 if (map[i][j]=='x') head=1,tail=0; 51 while (head<=tail&&f[last][i][j]>f[last][q[tail]][j]+i-q[tail]) tail--; 52 q[++tail]=i; 53 while (head<=tail&&i-len>q[head]) head++; 54 if (head<=tail) f[now][i][j]=max(f[now][i][j],f[last][q[head]][j]+i-q[head]); 55 } 56 } 57 break; 58 case 3: 59 for (int i=1;i<=n;i++) 60 { 61 int head=1,tail=0; 62 for (int j=m;j>=1;j--) 63 { 64 f[now][i][j]=f[last][i][j]; 65 if (map[i][j]=='x') head=1,tail=0; 66 while (head<=tail&&f[last][i][j]>f[last][i][q[tail]]+q[tail]-j) tail--; 67 q[++tail]=j; 68 while (head<=tail&&j+len<q[head]) head++; 69 if (head<=tail) f[now][i][j]=max(f[now][i][j],f[last][i][q[head]]+q[head]-j); 70 } 71 } 72 break; 73 case 4: 74 for (int i=1;i<=n;i++) 75 { 76 int head=1,tail=0; 77 for (int j=1;j<=m;j++) 78 { 79 f[now][i][j]=f[last][i][j]; 80 if (map[i][j]=='x') head=1,tail=0; 81 while (head<=tail&&f[last][i][j]>f[last][i][q[tail]]+j-q[tail]) tail--; 82 q[++tail]=j; 83 while (head<=tail&&j-len>q[head]) head++; 84 if (head<=tail) f[now][i][j]=max(f[now][i][j],f[last][i][q[head]]+j-q[head]); 85 } 86 } 87 break; 88 } 89 } 90 ans=0; 91 for (int i=1;i<=n;i++) 92 for (int j=1;j<=m;j++) 93 if (f[now][i][j]>ans) ans=f[now][i][j]; 94 printf("%d\n",ans); 95 return 0; 96 } 97
AC without art, no better than WA !