【Luogu】P2254瑰丽华尔兹(堆优化DP)
我也不知道为什么脑子一抽就想了个堆优化……然后贼慢……
因为上午听不懂wys的电音专场(快速傅立叶变换),然后就做了这么一道题。
首先朴素DP很sb都能秒出。就是枚举时刻、位置(两维)然后转移。
观察发现这是O(TNM)的,可以通过50%的数据。
然后……(喂题目提示得太明显了吧)发现时间段只有200个,跟50%的T是一样的
这简直就是明说:“快往O(KNM)上想!”
然后我就不知道为啥想了个O(KNMlogn),qwq。
枚举时刻改为枚举时间段,每个时间段枚举位置用堆优化(其实应该用单调队列)转移得出答案。
虽然题目水+我的方法慢+我是sb+实现方法诡异+调了很久,1A还是很高兴的。
(实现方法智障……可以当成锻炼代码能力嘛qwq)
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cctype> #define maxn 205 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } struct Node{ int dat,pos; bool operator <(const Node a)const{ return dat>a.dat; } bool operator <=(const Node a)const{ return dat>=a.dat; } }; struct Heap{ Node heap[505];int size; Heap(){ size=0;} inline void push(Node x){ heap[++size]=x; register int i=size,k; while(i>1){ k=i>>1; if(heap[k]<=heap[i]) return; swap(heap[i],heap[k]); i=k; } return; } inline bool empty(){ return !size; } inline Node top(){ return heap[1]; } inline void clear(){size=0;} inline void pop(){ heap[1]=heap[size--]; register int i=1,k; while((i<<1)<=size){ k=i<<1; if(k<size&&heap[k|1]<heap[k]) k|=1; if(heap[i]<=heap[k]) return; swap(heap[i],heap[k]); i=k; } } }; Heap s[maxn]; int last,now=1; int f[maxn][maxn][2]; char mp[maxn][maxn]; struct Line{ int from,to,dir; bool operator <(const Line a)const{ return from<a.from; } }q[maxn]; int main(){ int n=read(),m=read(),sx=read(),sy=read(),e=read(); for(int i=1;i<=n;++i) scanf("%s",mp[i]+1); for(int i=1;i<=e;++i) q[i]=(Line){read(),read(),read()}; sort(q+1,q+e+1); memset(f,-127/3,sizeof(f)); f[sx][sy][last]=0; for(int i=1;i<=e;++i){ int from=q[i].from,to=q[i].to,dir=q[i].dir; if(dir<3) for(int j=1;j<=m;++j){ s[j].clear(); if(dir==1){ int cnt=0; for(int k=n;k;--k){ f[k][j][now]=-100000000; cnt++; if(mp[k][j]=='x'){ s[j].clear(); continue; } if(s[j].empty()){ f[k][j][now]=f[k][j][last]; s[j].push((Node){f[k][j][last]-cnt,k}); continue; } Node ret=s[j].top(); while((!s[j].empty())&&ret.pos-k>to-from+1){ s[j].pop(); ret=s[j].top(); } if(s[j].empty()){ f[k][j][now]=f[k][j][last]; s[j].push((Node){f[k][j][last]-cnt,k}); continue; } //printf("%d %d %d %d\n",k,j,ret.pos,f[ret.pos][j][last]+ret.pos-k); f[k][j][now]=max(f[k][j][last],f[ret.pos][j][last]+ret.pos-k); s[j].push((Node){f[k][j][last]-cnt,k}); } } else{ int cnt=0; for(int k=1;k<=n;++k){ f[k][j][now]=-100000000; cnt++; if(mp[k][j]=='x'){ s[j].clear(); continue; } if(s[j].empty()){ f[k][j][now]=f[k][j][last]; s[j].push((Node){f[k][j][last]-cnt,k}); continue; } Node ret=s[j].top(); while((!s[j].empty())&&k-ret.pos>to-from+1){ s[j].pop(); ret=s[j].top(); } if(s[j].empty()){ f[k][j][now]=f[k][j][last]; s[j].push((Node){f[k][j][last]-cnt,k}); continue; } f[k][j][now]=max(f[k][j][last],f[ret.pos][j][last]+k-ret.pos); s[j].push((Node){f[k][j][last]-cnt,k}); } } } else for(int j=1;j<=n;++j){ s[j].clear(); if(dir==4){ int cnt=0; for(int k=1;k<=m;++k){ f[j][k][now]=-100000000; cnt++; if(mp[j][k]=='x'){ s[j].clear(); continue; } if(s[j].empty()){ f[j][k][now]=f[j][k][last]; s[j].push((Node){f[j][k][last]-cnt,k}); continue; } Node ret=s[j].top(); while((!s[j].empty())&&k-ret.pos>to-from+1){ s[j].pop(); ret=s[j].top(); } if(s[j].empty()){ f[j][k][now]=f[j][k][last]; s[j].push((Node){f[j][k][last]-cnt,k}); continue; } //printf("%d %d %d\n",j,k,f[j][ret.pos][last]+k-ret.pos); f[j][k][now]=max(f[j][k][last],f[j][ret.pos][last]+k-ret.pos); s[j].push((Node){f[j][k][last]-cnt,k}); } } else{ int cnt=0; for(int k=m;k;--k){ f[j][k][now]=-100000000; cnt++; if(mp[j][k]=='x'){ s[j].clear(); continue; } if(s[j].empty()){ f[j][k][now]=f[j][k][last]; s[j].push((Node){f[j][k][last]-cnt,k}); continue; } Node ret=s[j].top(); while((!s[j].empty())&&ret.pos-k>to-from+1){ s[j].pop(); ret=s[j].top(); } if(s[j].empty()){ f[j][k][now]=f[j][k][last]; s[j].push((Node){f[j][k][last]-cnt,k}); continue; } //printf("%d %d %d\n",j,k,f[j][ret.pos][last]+ret.pos-k); f[j][k][now]=max(f[j][k][last],f[j][ret.pos][last]+ret.pos-k); s[j].push((Node){f[j][k][last]-cnt,k}); } } } swap(now,last); } int ans=0; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) ans=max(ans,f[i][j][last]); printf("%d\n",ans); return 0; }