1. 程式人生 > >BZOJ1499: [NOI2005]瑰麗華爾茲

BZOJ1499: [NOI2005]瑰麗華爾茲

head main 方程 長時間 == 時間復雜度 php .com blog

【傳送門:BZOJ1499


簡要題意:

  有一個字符矩陣,‘.‘表示能走,‘x‘表示不能走,給出起點的坐標,起點有一座鋼琴,每單位時間可以移動一格,共有k個時間段,然後再給出每個時間段起始時間和結束時間,以及當前時間段能夠移動的方向。而在某個時間,可以控制鋼琴不動,鋼琴不能走到‘x‘而且不能走出矩陣

  求出鋼琴最多能走多少格


題解:

  一眼DP題

  設f[t][i][j]表示第t時間走到(i,j)最多能走的格數,f[t][i][j]=max(f[t-1][i][j],f[t-1][i-dx[i]][j-dy[i]]+1),時間復雜度O(nmT),超時

  我們重新搞DP方程,設f[k][i][j]表示第k時間段走到(i,j)最多能走的格數,f[k][i][j]=max(f[k][i][j],f[k-1][i-dx[i]*c][j-dy[i]*c]+c),c為第k-1時間段走多長時間

  因為每個時間段都是對於一行或者一列進行操作的,所以我們可以分成四種情況來單調隊列

  這樣子時間復雜度就是O(nmk)

  還要提的一點是,最好用滾動數組,優化一下空間


參考代碼:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
char st[210][210];
struct node
{
    int d,t;
}T[
210]; int f[2][210][210]; int list[210]; int main() { int n,m,x,y,k; scanf("%d%d%d%d%d",&n,&m,&x,&y,&k); for(int i=1;i<=n;i++) scanf("%s",st[i]+1); for(int i=1;i<=k;i++) { int l,r; scanf("%d%d%d",&l,&r,&T[i].t); T[i].d
=r-l+1; } memset(f,-63,sizeof(f)); f[0][x][y]=0; int now=0,last=1,head,tail; for(int K=1;K<=k;K++) { now^=1;last^=1; if(T[K].t==1) { for(int j=1;j<=m;j++) { head=1;tail=0; for(int i=n;i>=1;i--) { if(st[i][j]==x) head=1,tail=0; while(head<=tail&&list[head]-i>T[K].d) head++; if(head<=tail) f[now][i][j]=f[last][list[head]][j]+list[head]-i; while(head<=tail&&f[last][i][j]>f[last][list[tail]][j]+list[tail]-i) tail--; list[++tail]=i; f[now][i][j]=max(f[now][i][j],f[last][i][j]); } } } if(T[K].t==2) { for(int j=1;j<=m;j++) { head=1;tail=0; for(int i=1;i<=n;i++) { if(st[i][j]==x) head=1,tail=0; while(head<=tail&&i-list[head]>T[K].d) head++; if(head<=tail) f[now][i][j]=f[last][list[head]][j]+i-list[head]; while(head<=tail&&f[last][i][j]>f[last][list[tail]][j]+i-list[tail]) tail--; list[++tail]=i; f[now][i][j]=max(f[now][i][j],f[last][i][j]); } } } if(T[K].t==3) { for(int i=1;i<=n;i++) { head=1;tail=0; for(int j=m;j>=1;j--) { if(st[i][j]==x) head=1,tail=0; while(head<=tail&&list[head]-j>T[K].d) head++; if(head<=tail) f[now][i][j]=f[last][i][list[head]]+list[head]-j; while(head<=tail&&f[last][i][j]>f[last][i][list[tail]]+list[tail]-j) tail--; list[++tail]=j; f[now][i][j]=max(f[now][i][j],f[last][i][j]); } } } if(T[K].t==4) { for(int i=1;i<=n;i++) { head=1;tail=0; for(int j=1;j<=m;j++) { if(st[i][j]==x) head=1,tail=0; while(head<=tail&&j-list[head]>T[K].d) head++; if(head<=tail) f[now][i][j]=f[last][i][list[head]]+j-list[head]; while(head<=tail&&f[last][i][j]>f[last][i][list[tail]]+j-list[tail]) tail--; list[++tail]=j; f[now][i][j]=max(f[now][i][j],f[last][i][j]); } } } } int ans=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ans=max(f[now][i][j],ans); printf("%d\n",ans); return 0; }

BZOJ1499: [NOI2005]瑰麗華爾茲